Apply new errors processing to more code parts

This commit is contained in:
DarthSim
2025-02-18 17:35:13 +03:00
parent 2145a66174
commit 3550042a16
16 changed files with 109 additions and 57 deletions

View File

@@ -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)
}
}

View File

@@ -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
},

View File

@@ -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},

View File

@@ -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

View File

@@ -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
View 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) }

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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())

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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) }

View File

@@ -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

View File

@@ -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()