mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-09 11:42:48 +02:00
Apply new errors processing to more code parts
This commit is contained in:
@@ -10,8 +10,13 @@ import (
|
||||
"golang.org/x/net/publicsuffix"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
)
|
||||
|
||||
type cookieError string
|
||||
|
||||
func (e cookieError) Error() string { return string(e) }
|
||||
|
||||
type anyCookieJarEntry struct {
|
||||
Name string
|
||||
Value string
|
||||
@@ -75,7 +80,7 @@ func JarFromRequest(r *http.Request) (jar http.CookieJar, err error) {
|
||||
if !config.CookiePassthroughAll {
|
||||
if len(config.CookieBaseURL) > 0 {
|
||||
if cookieBase, err = url.Parse(config.CookieBaseURL); err != nil {
|
||||
return nil, fmt.Errorf("can't parse cookie base URL: %s", err)
|
||||
return nil, ierrors.Wrap(cookieError(fmt.Sprintf("can't parse cookie base URL: %s", err)), 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package imagedata
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
@@ -105,7 +104,7 @@ func initDownloading() error {
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
redirects := len(via)
|
||||
if redirects >= config.MaxRedirects {
|
||||
return fmt.Errorf("stopped after %d redirects", redirects)
|
||||
return newImageTooManyRedirectsError(redirects)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
@@ -15,6 +15,7 @@ type (
|
||||
ImageRequstSchemeError string
|
||||
ImagePartialResponseError string
|
||||
ImageResponseStatusError string
|
||||
ImageTooManyRedirectsError string
|
||||
ImageRequestCanceledError struct{ error }
|
||||
ImageRequestTimeoutError struct{ error }
|
||||
|
||||
@@ -90,6 +91,18 @@ func newImageResponseStatusError(status int, body string) error {
|
||||
|
||||
func (e ImageResponseStatusError) Error() string { return string(e) }
|
||||
|
||||
func newImageTooManyRedirectsError(n int) error {
|
||||
return ierrors.Wrap(
|
||||
ImageTooManyRedirectsError(fmt.Sprintf("Stopped after %d redirects", n)),
|
||||
1,
|
||||
ierrors.WithStatusCode(http.StatusNotFound),
|
||||
ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
|
||||
ierrors.WithShouldReport(false),
|
||||
)
|
||||
}
|
||||
|
||||
func (e ImageTooManyRedirectsError) Error() string { return string(e) }
|
||||
|
||||
func newImageRequestCanceledError(err error) error {
|
||||
return ierrors.Wrap(
|
||||
ImageRequestCanceledError{err},
|
||||
|
@@ -185,7 +185,7 @@ func heifReadHldr(r io.Reader, boxDataSize uint64) error {
|
||||
}
|
||||
|
||||
if !bytes.Equal(data[8:12], heifPict) {
|
||||
return fmt.Errorf("Invalid handler. Expected: pict, actual: %s", data[8:12])
|
||||
return newFormatError("HEIF", fmt.Sprintf("Invalid handler. Expected: pict, actual: %s", data[8:12]))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -2,7 +2,6 @@ package options
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -35,11 +34,11 @@ func decodeBase64URL(parts []string) (string, string, error) {
|
||||
urlParts := strings.Split(encoded, ".")
|
||||
|
||||
if len(urlParts[0]) == 0 {
|
||||
return "", "", errors.New("Image URL is empty")
|
||||
return "", "", newInvalidURLError("Image URL is empty")
|
||||
}
|
||||
|
||||
if len(urlParts) > 2 {
|
||||
return "", "", fmt.Errorf("Multiple formats are specified: %s", encoded)
|
||||
return "", "", newInvalidURLError("Multiple formats are specified: %s", encoded)
|
||||
}
|
||||
|
||||
if len(urlParts) == 2 && len(urlParts[1]) > 0 {
|
||||
@@ -48,7 +47,7 @@ func decodeBase64URL(parts []string) (string, string, error) {
|
||||
|
||||
imageURL, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(urlParts[0], "="))
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
||||
return "", "", newInvalidURLError("Invalid url encoding: %s", encoded)
|
||||
}
|
||||
|
||||
return preprocessURL(string(imageURL)), format, nil
|
||||
@@ -61,11 +60,11 @@ func decodePlainURL(parts []string) (string, string, error) {
|
||||
urlParts := strings.Split(encoded, "@")
|
||||
|
||||
if len(urlParts[0]) == 0 {
|
||||
return "", "", errors.New("Image URL is empty")
|
||||
return "", "", newInvalidURLError("Image URL is empty")
|
||||
}
|
||||
|
||||
if len(urlParts) > 2 {
|
||||
return "", "", fmt.Errorf("Multiple formats are specified: %s", encoded)
|
||||
return "", "", newInvalidURLError("Multiple formats are specified: %s", encoded)
|
||||
}
|
||||
|
||||
if len(urlParts) == 2 && len(urlParts[1]) > 0 {
|
||||
@@ -74,7 +73,7 @@ func decodePlainURL(parts []string) (string, string, error) {
|
||||
|
||||
unescaped, err := url.PathUnescape(urlParts[0])
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
||||
return "", "", newInvalidURLError("Invalid url encoding: %s", encoded)
|
||||
}
|
||||
|
||||
return preprocessURL(unescaped), format, nil
|
||||
@@ -82,7 +81,7 @@ func decodePlainURL(parts []string) (string, string, error) {
|
||||
|
||||
func DecodeURL(parts []string) (string, string, error) {
|
||||
if len(parts) == 0 {
|
||||
return "", "", errors.New("Image URL is empty")
|
||||
return "", "", newInvalidURLError("Image URL is empty")
|
||||
}
|
||||
|
||||
if parts[0] == urlTokenPlain && len(parts) > 1 {
|
||||
|
25
processing/errors.go
Normal file
25
processing/errors.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package processing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
"github.com/imgproxy/imgproxy/v3/imagetype"
|
||||
)
|
||||
|
||||
type (
|
||||
SaveFormatError string
|
||||
)
|
||||
|
||||
func newSaveFormatError(format imagetype.Type) error {
|
||||
return ierrors.Wrap(
|
||||
SaveFormatError(fmt.Sprintf("Can't save %s, probably not supported by your libvips", format)),
|
||||
1,
|
||||
ierrors.WithStatusCode(http.StatusUnprocessableEntity),
|
||||
ierrors.WithPublicMessage("Invalid URL"),
|
||||
ierrors.WithShouldReport(false),
|
||||
)
|
||||
}
|
||||
|
||||
func (e SaveFormatError) Error() string { return string(e) }
|
@@ -3,7 +3,6 @@ package processing
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
@@ -301,7 +300,7 @@ func ProcessImage(ctx context.Context, imgdata *imagedata.ImageData, po *options
|
||||
}
|
||||
|
||||
if !vips.SupportsSave(po.Format) {
|
||||
return nil, fmt.Errorf("Can't save %s, probably not supported by your libvips", po.Format)
|
||||
return nil, newSaveFormatError(po.Format)
|
||||
}
|
||||
|
||||
if po.Format.SupportsAnimationSave() && animated {
|
||||
|
@@ -109,7 +109,7 @@ func (t transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if r := req.Header.Get("Range"); len(r) != 0 {
|
||||
start, end, err := httprange.Parse(r)
|
||||
if err != nil {
|
||||
return httprange.InvalidHTTPRangeResponse(req), err
|
||||
return httprange.InvalidHTTPRangeResponse(req), nil
|
||||
}
|
||||
|
||||
if end != 0 {
|
||||
|
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/httprange"
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
defaultTransport "github.com/imgproxy/imgproxy/v3/transport"
|
||||
"github.com/imgproxy/imgproxy/v3/transport/common"
|
||||
"github.com/imgproxy/imgproxy/v3/transport/notmodified"
|
||||
@@ -71,7 +72,7 @@ func New() (http.RoundTripper, error) {
|
||||
client, err = storage.NewClient(context.Background(), opts...)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't create GCS client: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("Can't create GCS client"))
|
||||
}
|
||||
|
||||
return transport{client}, nil
|
||||
|
@@ -3,7 +3,6 @@ package s3
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -23,6 +22,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
defaultTransport "github.com/imgproxy/imgproxy/v3/transport"
|
||||
"github.com/imgproxy/imgproxy/v3/transport/common"
|
||||
)
|
||||
@@ -48,7 +48,7 @@ type transport struct {
|
||||
func New() (http.RoundTripper, error) {
|
||||
conf, err := awsConfig.LoadDefaultConfig(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load AWS S3 config: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("can't load AWS S3 config"))
|
||||
}
|
||||
|
||||
trans, err := defaultTransport.New(false)
|
||||
@@ -90,7 +90,7 @@ func New() (http.RoundTripper, error) {
|
||||
|
||||
client, err := createClient(conf, clientOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't create S3 client: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("can't create S3 client"))
|
||||
}
|
||||
|
||||
return &transport{
|
||||
@@ -248,7 +248,7 @@ func (t *transport) getClient(ctx context.Context, bucket string) (s3Client, err
|
||||
|
||||
region, err := s3Manager.GetBucketRegion(ctx, t.defaultClient, bucket)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get bucket region: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("can't get bucket region"))
|
||||
}
|
||||
|
||||
if len(region) == 0 {
|
||||
@@ -265,7 +265,7 @@ func (t *transport) getClient(ctx context.Context, bucket string) (s3Client, err
|
||||
|
||||
client, err = createClient(conf, t.clientOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't create regional S3 client: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("can't create regional S3 client"))
|
||||
}
|
||||
|
||||
t.clientsByRegion[region] = client
|
||||
@@ -295,11 +295,11 @@ func createClient(conf aws.Config, opts []func(*s3.Options)) (s3Client, error) {
|
||||
func handleError(req *http.Request, err error) (*http.Response, error) {
|
||||
var rerr *awsHttp.ResponseError
|
||||
if !errors.As(err, &rerr) {
|
||||
return nil, err
|
||||
return nil, ierrors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
if rerr.Response == nil || rerr.Response.StatusCode < 100 || rerr.Response.StatusCode == 301 {
|
||||
return nil, err
|
||||
return nil, ierrors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
body := strings.NewReader(err.Error())
|
||||
|
@@ -3,7 +3,6 @@ package swift
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
"github.com/ncw/swift/v2"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
defaultTransport "github.com/imgproxy/imgproxy/v3/transport"
|
||||
"github.com/imgproxy/imgproxy/v3/transport/common"
|
||||
"github.com/imgproxy/imgproxy/v3/transport/notmodified"
|
||||
@@ -44,7 +44,7 @@ func New() (http.RoundTripper, error) {
|
||||
err = c.Authenticate(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("swift authentication error: %s", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("swift authentication error"))
|
||||
}
|
||||
|
||||
return transport{con: c}, nil
|
||||
@@ -91,7 +91,7 @@ func (t transport) RoundTrip(req *http.Request) (resp *http.Response, err error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("error opening object: %v", err)
|
||||
return nil, ierrors.Wrap(err, 0, ierrors.WithPrefix("error opening object"))
|
||||
}
|
||||
|
||||
if config.ETagEnabled {
|
||||
|
21
vips/bmp.go
21
vips/bmp.go
@@ -9,7 +9,6 @@ import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"unsafe"
|
||||
|
||||
@@ -36,10 +35,6 @@ type bmpHeader struct {
|
||||
colorImportant uint32
|
||||
}
|
||||
|
||||
// errBmpUnsupported means that the input BMP image uses a valid but unsupported
|
||||
// feature.
|
||||
var errBmpUnsupported = errors.New("unsupported BMP image")
|
||||
|
||||
func readUint16(b []byte) uint16 {
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
@@ -264,7 +259,7 @@ Loop:
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func (img *Image) decodeBmpRGB(r io.Reader, width, height, bands int, topDown, noAlpha bool) error {
|
||||
if bands != 3 && bands != 4 {
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
imgBands := 3
|
||||
@@ -381,13 +376,13 @@ func (img *Image) loadBmp(data []byte, noAlpha bool) error {
|
||||
}
|
||||
|
||||
if string(b[:2]) != "BM" {
|
||||
return errors.New("not a BMP image")
|
||||
return newVipsError("not a BMP image")
|
||||
}
|
||||
|
||||
offset := readUint32(b[10:14])
|
||||
infoLen := readUint32(b[14:18])
|
||||
if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen {
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
|
||||
@@ -405,14 +400,14 @@ func (img *Image) loadBmp(data []byte, noAlpha bool) error {
|
||||
height, topDown = -height, true
|
||||
}
|
||||
if width <= 0 || height <= 0 {
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
// We only support 1 plane and 8, 24 or 32 bits per pixel
|
||||
planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
|
||||
|
||||
if planes != 1 {
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
rle := false
|
||||
@@ -447,10 +442,10 @@ func (img *Image) loadBmp(data []byte, noAlpha bool) error {
|
||||
case bpp == 32 && rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff && amask == 0xff000000:
|
||||
// Go ahead, it's a regular 32-bit image
|
||||
default:
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
default:
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
var palette []Color
|
||||
@@ -497,7 +492,7 @@ func (img *Image) loadBmp(data []byte, noAlpha bool) error {
|
||||
return img.decodeBmpRGB(r, width, height, 4, topDown, noAlpha)
|
||||
}
|
||||
|
||||
return errBmpUnsupported
|
||||
return newVipsError("unsupported BMP image")
|
||||
}
|
||||
|
||||
func (img *Image) saveAsBmp() (*imagedata.ImageData, error) {
|
||||
|
@@ -18,7 +18,7 @@ func ColorFromHex(hexcolor string) (Color, error) {
|
||||
c := Color{}
|
||||
|
||||
if !hexColorRegex.MatchString(hexcolor) {
|
||||
return c, fmt.Errorf("Invalid hex color: %s", hexcolor)
|
||||
return c, newColorError("Invalid hex color: %s", hexcolor)
|
||||
}
|
||||
|
||||
if len(hexcolor) == 3 {
|
||||
|
@@ -1,13 +1,32 @@
|
||||
package vips
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
)
|
||||
|
||||
type VipsError string
|
||||
type (
|
||||
VipsError string
|
||||
ColorError string
|
||||
)
|
||||
|
||||
func newVipsError(msg string) error {
|
||||
return ierrors.Wrap(VipsError(msg), 2)
|
||||
return ierrors.Wrap(VipsError(msg), 1)
|
||||
}
|
||||
|
||||
func newVipsErrorf(format string, args ...interface{}) error {
|
||||
return ierrors.Wrap(VipsError(fmt.Sprintf(format, args...)), 1)
|
||||
}
|
||||
|
||||
func (e VipsError) Error() string { return string(e) }
|
||||
|
||||
func newColorError(format string, args ...interface{}) error {
|
||||
return ierrors.Wrap(
|
||||
ColorError(fmt.Sprintf(format, args...)),
|
||||
1,
|
||||
ierrors.WithShouldReport(false),
|
||||
)
|
||||
}
|
||||
|
||||
func (e ColorError) Error() string { return string(e) }
|
||||
|
@@ -7,8 +7,6 @@ import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/imagedata"
|
||||
@@ -43,7 +41,7 @@ func (img *Image) loadIco(data []byte, shrink int, scale float64, pages int) err
|
||||
internalType = meta.Format()
|
||||
|
||||
if internalType == imagetype.ICO || !SupportsLoad(internalType) {
|
||||
return fmt.Errorf("Can't load %s from ICO", internalType)
|
||||
return newVipsErrorf("Can't load %s from ICO", internalType)
|
||||
}
|
||||
|
||||
imgdata := imagedata.ImageData{
|
||||
@@ -56,7 +54,7 @@ func (img *Image) loadIco(data []byte, shrink int, scale float64, pages int) err
|
||||
|
||||
func (img *Image) saveAsIco() (*imagedata.ImageData, error) {
|
||||
if img.Width() > 256 || img.Height() > 256 {
|
||||
return nil, errors.New("Image dimensions is too big. Max dimension size for ICO is 256")
|
||||
return nil, newVipsError("Image dimensions is too big. Max dimension size for ICO is 256")
|
||||
}
|
||||
|
||||
var ptr unsafe.Pointer
|
||||
|
@@ -9,7 +9,6 @@ package vips
|
||||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -69,7 +68,7 @@ func Init() error {
|
||||
|
||||
if err := C.vips_initialize(); err != 0 {
|
||||
C.vips_shutdown()
|
||||
return errors.New("unable to start vips!")
|
||||
return newVipsError("unable to start vips!")
|
||||
}
|
||||
|
||||
// Disable libvips cache. Since processing pipeline is fine tuned, we won't get much profit from it.
|
||||
@@ -355,7 +354,7 @@ func (img *Image) Load(imgdata *imagedata.ImageData, shrink int, scale float64,
|
||||
case imagetype.TIFF:
|
||||
err = C.vips_tiffload_go(data, dataSize, &tmp)
|
||||
default:
|
||||
return errors.New("Usupported image type to load")
|
||||
return newVipsError("Usupported image type to load")
|
||||
}
|
||||
if err != 0 {
|
||||
return Error()
|
||||
@@ -376,7 +375,7 @@ func (img *Image) Load(imgdata *imagedata.ImageData, shrink int, scale float64,
|
||||
|
||||
func (img *Image) LoadThumbnail(imgdata *imagedata.ImageData) error {
|
||||
if imgdata.Type != imagetype.HEIC && imgdata.Type != imagetype.AVIF {
|
||||
return errors.New("Usupported image type to load thumbnail")
|
||||
return newVipsError("Usupported image type to load thumbnail")
|
||||
}
|
||||
|
||||
var tmp *C.VipsImage
|
||||
@@ -428,7 +427,7 @@ func (img *Image) Save(imgtype imagetype.Type, quality int) (*imagedata.ImageDat
|
||||
case imagetype.TIFF:
|
||||
err = C.vips_tiffsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
|
||||
default:
|
||||
return nil, errors.New("Usupported image type to save")
|
||||
return nil, newVipsError("Usupported image type to save")
|
||||
}
|
||||
if err != 0 {
|
||||
cancel()
|
||||
|
Reference in New Issue
Block a user