From 5dcad5430a1ff89b4b5b1831034a9df31feedc4a Mon Sep 17 00:00:00 2001 From: DarthSim Date: Fri, 7 Sep 2018 19:37:25 +0600 Subject: [PATCH] Advanced url format --- process.go | 15 --- processing_options.go | 288 ++++++++++++++++++++++++++++++++++++++++++ server.go | 63 --------- 3 files changed, 288 insertions(+), 78 deletions(-) create mode 100644 processing_options.go diff --git a/process.go b/process.go index 4cdb7355..a86f640a 100644 --- a/process.go +++ b/process.go @@ -62,21 +62,6 @@ const ( CROP ) -var resizeTypes = map[string]resizeType{ - "fit": FIT, - "fill": FILL, - "crop": CROP, -} - -type processingOptions struct { - Resize resizeType - Width int - Height int - Gravity gravityType - Enlarge bool - Format imageType -} - var vipsSupportSmartcrop bool var vipsTypeSupportLoad = make(map[imageType]bool) var vipsTypeSupportSave = make(map[imageType]bool) diff --git a/processing_options.go b/processing_options.go new file mode 100644 index 00000000..a2f3338f --- /dev/null +++ b/processing_options.go @@ -0,0 +1,288 @@ +package main + +import ( + "C" + "encoding/base64" + "errors" + "fmt" + "net/http" + "strconv" + "strings" +) + +var resizeTypes = map[string]resizeType{ + "fit": FIT, + "fill": FILL, + "crop": CROP, +} + +type processingOptions struct { + Resize resizeType + Width int + Height int + Gravity gravityType + Enlarge bool + Format imageType +} + +func defaultProcessingOptions() processingOptions { + return processingOptions{ + Resize: FIT, + Width: 0, + Height: 0, + Gravity: CENTER, + Enlarge: false, + Format: JPEG, + } +} + +func decodeUrl(parts []string) (string, imageType, error) { + var imgType imageType = JPEG + + urlParts := strings.Split(strings.Join(parts, ""), ".") + + if len(urlParts) > 2 { + return "", 0, errors.New("Invalid url encoding") + } + + if len(urlParts) == 2 { + if f, ok := imageTypes[urlParts[1]]; ok { + imgType = f + } else { + return "", 0, fmt.Errorf("Invalid image format: %s", urlParts[1]) + } + } + + url, err := base64.RawURLEncoding.DecodeString(urlParts[0]) + if err != nil { + return "", 0, errors.New("Invalid url encoding") + } + + return string(url), imgType, nil +} + +func applyWidthOption(po *processingOptions, args []string) error { + if len(args) > 1 { + return fmt.Errorf("Invalid width arguments: %v", args) + } + + if w, err := strconv.Atoi(args[0]); err == nil || w >= 0 { + po.Width = w + } else { + return fmt.Errorf("Invalid width: %s", args[0]) + } + + return nil +} + +func applyHeightOption(po *processingOptions, args []string) error { + if len(args) > 1 { + return fmt.Errorf("Invalid height arguments: %v", args) + } + + if h, err := strconv.Atoi(args[0]); err == nil || po.Height >= 0 { + po.Height = h + } else { + return fmt.Errorf("Invalid height: %s", args[0]) + } + + return nil +} + +func applyEnlargeOption(po *processingOptions, args []string) error { + if len(args) > 1 { + return fmt.Errorf("Invalid enlarge arguments: %v", args) + } + + po.Enlarge = args[0] != "0" + + return nil +} + +func applySizeOption(po *processingOptions, args []string) (err error) { + if len(args) > 3 { + return fmt.Errorf("Invalid size arguments: %v", args) + } + + if len(args) >= 1 { + if err = applyWidthOption(po, args[0:1]); err != nil { + return + } + } + + if len(args) >= 2 { + if err = applyHeightOption(po, args[1:2]); err != nil { + return + } + } + + if len(args) == 3 { + if err = applyEnlargeOption(po, args[2:3]); err != nil { + return + } + } + + return nil +} + +func applyResizeOption(po *processingOptions, args []string) error { + if len(args) > 4 { + return fmt.Errorf("Invalid resize arguments: %v", args) + } + + if r, ok := resizeTypes[args[0]]; ok { + po.Resize = r + } else { + return fmt.Errorf("Invalid resize type: %s", args[0]) + } + + if len(args) > 1 { + if err := applySizeOption(po, args[1:]); err != nil { + return err + } + } + + return nil +} + +func applyGravityOption(po *processingOptions, args []string) error { + if len(args) > 1 { + return fmt.Errorf("Invalid resize arguments: %v", args) + } + + if g, ok := gravityTypes[args[0]]; ok { + po.Gravity = g + } else { + return fmt.Errorf("Invalid gravity: %s", args[0]) + } + + return nil +} + +func applyFormatOption(po *processingOptions, imgType imageType) error { + if !vipsTypeSupportSave[imgType] { + return errors.New("Resulting image type not supported") + } + + po.Format = imgType + + return nil +} + +func applyProcessingOption(po *processingOptions, name string, args []string) error { + switch name { + case "resize": + if err := applyResizeOption(po, args); err != nil { + return err + } + case "size": + if err := applySizeOption(po, args); err != nil { + return err + } + case "width": + if err := applyWidthOption(po, args); err != nil { + return err + } + case "height": + if err := applyHeightOption(po, args); err != nil { + return err + } + case "enlarge": + if err := applyEnlargeOption(po, args); err != nil { + return err + } + case "gravity": + if err := applyGravityOption(po, args); err != nil { + return err + } + } + + return nil +} + +func parsePathAdvanced(parts []string) (string, processingOptions, error) { + var urlStart int + + po := defaultProcessingOptions() + + for i, part := range parts { + args := strings.Split(part, ":") + + if len(args) == 1 { + urlStart = i + break + } + + if err := applyProcessingOption(&po, args[0], args[1:]); err != nil { + return "", po, err + } + } + + url, imgType, err := decodeUrl(parts[urlStart:]) + if err != nil { + return "", po, err + } + + if err := applyFormatOption(&po, imgType); err != nil { + return "", po, errors.New("Resulting image type not supported") + } + + return string(url), po, nil +} + +func parsePathSimple(parts []string) (string, processingOptions, error) { + var po processingOptions + var err error + + if len(parts) < 6 { + return "", po, errors.New("Invalid path") + } + + po.Resize = resizeTypes[parts[0]] + + if err = applyWidthOption(&po, parts[1:2]); err != nil { + return "", po, err + } + + if err = applyHeightOption(&po, parts[2:3]); err != nil { + return "", po, err + } + + if err = applyGravityOption(&po, parts[3:4]); err != nil { + return "", po, err + } + + if err = applyEnlargeOption(&po, parts[4:5]); err != nil { + return "", po, err + } + + url, imgType, err := decodeUrl(parts[5:]) + if err != nil { + return "", po, err + } + + if err := applyFormatOption(&po, imgType); err != nil { + return "", po, errors.New("Resulting image type not supported") + } + + return string(url), po, nil +} + +func parsePath(r *http.Request) (string, processingOptions, error) { + path := r.URL.Path + parts := strings.Split(strings.TrimPrefix(path, "/"), "/") + + if len(parts) < 3 { + return "", processingOptions{}, errors.New("Invalid path") + } + + // if err := validatePath(parts[0], strings.TrimPrefix(path, fmt.Sprintf("/%s", parts[0]))); err != nil { + // return "", processingOptions{}, err + // } + + if _, ok := resizeTypes[parts[1]]; ok { + return parsePathSimple(parts[1:]) + } else { + return parsePathAdvanced(parts[1:]) + } +} diff --git a/server.go b/server.go index e6178b09..63762965 100644 --- a/server.go +++ b/server.go @@ -5,8 +5,6 @@ import ( "compress/gzip" "context" "crypto/subtle" - "encoding/base64" - "errors" "fmt" "log" "net" @@ -63,67 +61,6 @@ func shutdownServer(s *http.Server) { s.Shutdown(ctx) } -func parsePath(r *http.Request) (string, processingOptions, error) { - var po processingOptions - var err error - - path := r.URL.Path - parts := strings.Split(strings.TrimPrefix(path, "/"), "/") - - if len(parts) < 7 { - return "", po, errors.New("Invalid path") - } - - token := parts[0] - - if err = validatePath(token, strings.TrimPrefix(path, fmt.Sprintf("/%s", token))); err != nil { - return "", po, err - } - - if r, ok := resizeTypes[parts[1]]; ok { - po.Resize = r - } else { - return "", po, fmt.Errorf("Invalid resize type: %s", parts[1]) - } - - if po.Width, err = strconv.Atoi(parts[2]); err != nil { - return "", po, fmt.Errorf("Invalid width: %s", parts[2]) - } - - if po.Height, err = strconv.Atoi(parts[3]); err != nil { - return "", po, fmt.Errorf("Invalid height: %s", parts[3]) - } - - if g, ok := gravityTypes[parts[4]]; ok { - po.Gravity = g - } else { - return "", po, fmt.Errorf("Invalid gravity: %s", parts[4]) - } - - po.Enlarge = parts[5] != "0" - - filenameParts := strings.Split(strings.Join(parts[6:], ""), ".") - - if len(filenameParts) < 2 { - po.Format = imageTypes["jpg"] - } else if f, ok := imageTypes[filenameParts[1]]; ok { - po.Format = f - } else { - return "", po, fmt.Errorf("Invalid image format: %s", filenameParts[1]) - } - - if !vipsTypeSupportSave[po.Format] { - return "", po, errors.New("Resulting image type not supported") - } - - filename, err := base64.RawURLEncoding.DecodeString(filenameParts[0]) - if err != nil { - return "", po, errors.New("Invalid filename encoding") - } - - return string(filename), po, nil -} - func logResponse(status int, msg string) { var color int