diff --git a/Dockerfile b/Dockerfile index cba8ec0..25f1b01 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,14 @@ FROM golang:latest - -MAINTAINER Andreas Neue - RUN apt -y update && \ apt -y upgrade && \ apt -y install libglib2.0-dev libexpat1-dev libjpeg-dev libpng-dev libgif-dev - WORKDIR /go/src/image-resizer COPY . . - RUN wget https://github.com/libvips/libvips/releases/download/v8.7.3/vips-8.7.3.tar.gz && \ tar xvzf vips-8.7.3.tar.gz && \ cd vips-8.7.3 && \ ./configure && \ make && \ make install && \ - go get -v -u github.com/davidbyttow/govips/pkg/vips && \ - go install -v ./... - -CMD ["image-resizer", "-s", "https://images.example.com/"] + ldconfig +RUN go get -v -u github.com/davidbyttow/govips/pkg/vips && go install -v ./... diff --git a/main.go b/main.go index eee402a..2ee5b51 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,83 @@ func init() { flag.Parse() } +func resizeHandler(w http.ResponseWriter, r *http.Request) { + // Get the query parameters from the request URL + path := r.URL.EscapedPath() + parm := strings.Split(path, "/") + if len(parm) < 4 { + writeError(w, "", "", "error in arguments", http.StatusBadRequest) + return + } + + method := parm[1] + args := parm[2] + imgPath := strings.Join(parm[3:], "/") + + // Start fetching the image from the given url + resp, err := http.Get(*imgServer + imgPath) + if err != nil { + writeError(w, imgPath, method, "failed to fetch image", http.StatusNotFound) + return + } + defer resp.Body.Close() + + switch method { + case "resize": + 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 + } + + // govips returns the output of the image as a []byte object. We don't need + // it since we are directly piping it to the ResponseWriter + _, _, err = vips.NewTransform(). + Load(resp.Body). + ResizeStrategy(vips.ResizeStrategyEmbed). + Resize(iw, ih). + Output(w). + Apply() + + if err != nil { + writeError(w, imgPath, method, "failed to resize", http.StatusInternalServerError) + return + } + + default: + writeError(w, imgPath, method, "unknown method", http.StatusBadRequest) + return + } + +} + +func writeError(w http.ResponseWriter, imgPath, method, err string, status int) { + w.WriteHeader(status) + w.Write([]byte(fmt.Sprintf("Error [%s %s]: %s", method, imgPath, err))) +} + func main() { // Start vips with the default configuration vips.Startup(nil) @@ -30,70 +107,3 @@ func main() { http.HandleFunc("/", resizeHandler) log.Fatal(http.ListenAndServe(*listenAddr, nil)) } - -func resizeHandler(w http.ResponseWriter, r *http.Request) { - // Get the query parameters from the request URL - path := r.URL.EscapedPath() - parm := strings.Split(path, "/") - if len(parm) < 3 { - w.Write([]byte(fmt.Sprintf("url, width and height are required"))) - w.WriteHeader(http.StatusBadRequest) - return - } - queryUrl := parm[2] - size := strings.Split(parm[1], "x") - if len(size) < 2 { - w.Write([]byte(fmt.Sprintf("url, width and height are required"))) - w.WriteHeader(http.StatusBadRequest) - return - } - queryWidth := size[0] - queryHeight := size[1] - - // Validate that all three required fields are present - if queryUrl == "" || queryWidth == "" || queryHeight == "" { - w.Write([]byte(fmt.Sprintf("url, width and height are required"))) - w.WriteHeader(http.StatusBadRequest) - return - } - - // Convert width and height to integers - width, errW := strconv.Atoi(queryWidth) - height, errH := strconv.Atoi(queryHeight) - if errW != nil || errH != nil { - w.Write([]byte(fmt.Sprintf("width and height must be integers"))) - w.WriteHeader(http.StatusBadRequest) - return - } - - // Start fetching the image from the given url - resp, err := http.Get(*imgServer + queryUrl) - if err != nil { - w.Write([]byte(fmt.Sprintf("failed to get %s: %v", queryUrl, err))) - w.WriteHeader(http.StatusBadRequest) - return - } - - // Ensure that a valid response was given - if resp.StatusCode/100 != 2 { - w.Write([]byte(fmt.Sprintf("failed to get %s: status %d", queryUrl, resp.StatusCode))) - w.WriteHeader(http.StatusBadRequest) - return - } - defer resp.Body.Close() - - // govips returns the output of the image as a []byte object. We don't need - // it since we are directly piping it to the ResponseWriter - _, _, err = vips.NewTransform(). - Load(resp.Body). - ResizeStrategy(vips.ResizeStrategyStretch). - Resize(width, height). - Output(w). - Apply() - - if err != nil { - w.Write([]byte(fmt.Sprintf("failed to resize %s: %v", queryUrl, err))) - w.WriteHeader(http.StatusInternalServerError) - return - } -}