diff --git a/main.go b/main.go index a08d899..03b40d0 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,12 @@ -// vi:ts=4:sts=4:sw=4:noet:tw=72 +// (c) 2018 Karthik Karanth (https://github.com/medakk/gotiny) +// (c) 2018-2021 Andreas Neue package main import ( "flag" "fmt" + "io" "log" "net/http" "strconv" @@ -23,7 +25,7 @@ func init() { flag.Parse() } -func resizeHandler(w http.ResponseWriter, r *http.Request) { +func transform(w http.ResponseWriter, r *http.Request) { // Get the query parameters from the request URL path := r.URL.EscapedPath() parm := strings.Split(path, "/") @@ -43,81 +45,92 @@ func resizeHandler(w http.ResponseWriter, r *http.Request) { return } defer resp.Body.Close() + // Ensure that a valid response was given + if resp.StatusCode/100 != 2 { + writeError(w, imgPath, method, fmt.Sprintf("failed to fetch image (%v)", resp.StatusCode), http.StatusBadRequest) + return + } + + buf := []byte{} + errMsg := "" + errCode := 200 switch method { - case "resize": - allowed := strings.Split(*sizesFilter, ",") - forbidden := true - if allowed[0] == "*" { - forbidden = false - } else { - for _, v := range allowed { - if args == v { - forbidden = false - break - } - } - } - if forbidden { - writeError(w, imgPath, method, "size is not allowed", http.StatusForbidden) - return - } - - size := strings.Split(args, "x") - if len(size) < 2 { - writeError(w, imgPath, method, "url, width, and height are required", http.StatusBadRequest) - return - } - width := size[0] - height := size[1] - - // Validate that all three required fields are present - if imgPath == "" || width == "" || height == "" { - writeError(w, imgPath, method, "url, width, and height are required", http.StatusBadRequest) - return - } - - // Convert width and height to integers - iw, errW := strconv.Atoi(width) - ih, errH := strconv.Atoi(height) - if errW != nil || errH != nil { - writeError(w, imgPath, method, "width and height must be integers", http.StatusBadRequest) - return - } - - // Ensure that a valid response was given - if resp.StatusCode/100 != 2 { - writeError(w, imgPath, method, fmt.Sprintf("failed to fetch image (%v)", resp.StatusCode), http.StatusBadRequest) - return - } - - // Read from response body, convert and write to output buffer - img, err := vips.NewImageFromReader(resp.Body) - if err != nil { - writeError(w, imgPath, method, fmt.Sprintf("%v", err), http.StatusInternalServerError) - return - } - err = img.Thumbnail(iw, ih, 0) - if err != nil { - writeError(w, imgPath, method, fmt.Sprintf("%v", err), http.StatusInternalServerError) - return - } - ep := vips.NewDefaultExportParams() // default export params are sufficient - buf, _, _ := img.Export(ep) - _, err = w.Write(buf) - if err != nil { - writeError(w, imgPath, method, fmt.Sprintf("%v", err), http.StatusInternalServerError) - return - } - + case "pass": + break + case "resize": + buf, errMsg, errCode = doResize(resp.Body, args) + if buf == nil { + writeError(w, imgPath, method, errMsg, errCode) + } + case "thumbnail": + break default: writeError(w, imgPath, method, "unknown method", http.StatusBadRequest) return } + _, err = w.Write(buf) + if err != nil { + writeError(w, imgPath, method, fmt.Sprintf("%v", err), http.StatusInternalServerError) + return + } +} + +func doResize(body io.ReadCloser, args string) ([]byte, string, int) { + allowed := strings.Split(*sizesFilter, ",") + forbidden := true + if allowed[0] == "*" { + forbidden = false + } else { + for _, v := range allowed { + if args == v { + forbidden = false + break + } + } + } + if forbidden { + return nil, "size is not allowed", http.StatusForbidden + } + + size := strings.Split(args, "x") + if len(size) < 2 { + return nil, "width and height are required", http.StatusBadRequest + } + width := size[0] + height := size[1] + + // Validate that all three required fields are present + if width == "" || height == "" { + return nil, "width and height are required", http.StatusBadRequest + } + + // Convert width and height to integers + iw, errW := strconv.Atoi(width) + ih, errH := strconv.Atoi(height) + if errW != nil || errH != nil { + return nil, "width and height must be integers", http.StatusBadRequest + } + + // Read from response body, convert and write to output buffer + img, err := vips.NewImageFromReader(body) + if err != nil { + return nil, fmt.Sprintf("%v", err), http.StatusInternalServerError + } + err = img.Thumbnail(iw, ih, 0) + if err != nil { + return nil, fmt.Sprintf("%v", err), http.StatusInternalServerError + } + ep := vips.NewDefaultExportParams() // default export params are sufficient + buf, _, _ := img.Export(ep) + if err != nil { + return nil, fmt.Sprintf("%v", err), http.StatusInternalServerError + } + return buf, "", 0 } func writeError(w http.ResponseWriter, imgPath, method, err string, status int) { @@ -130,6 +143,6 @@ func main() { vips.Startup(nil) defer vips.Shutdown() - http.HandleFunc("/", resizeHandler) + http.HandleFunc("/", transform) log.Fatal(http.ListenAndServe(*listenAddr, nil)) }