diff --git a/cache-images.go b/cache-images.go index 84a4256..4e75b58 100644 --- a/cache-images.go +++ b/cache-images.go @@ -142,26 +142,12 @@ func cacheImage(imageURL, imageID string, imageType string) (string, bool, error return cachedImagePath, true, nil } - // Decode the image based on the content type - var img image.Image - switch contentType { - case "image/x-icon", "image/vnd.microsoft.icon": - img, err = ico.Decode(bytes.NewReader(data)) - case "image/jpeg": - img, err = jpeg.Decode(bytes.NewReader(data)) - case "image/png": - img, err = png.Decode(bytes.NewReader(data)) - case "image/gif": - img, err = gif.Decode(bytes.NewReader(data)) - case "image/webp": - img, err = webp.Decode(bytes.NewReader(data)) - case "image/bmp": - img, err = bmp.Decode(bytes.NewReader(data)) - case "image/tiff": - img, err = tiff.Decode(bytes.NewReader(data)) - default: + // Decode image + img, err := safeDecodeImage(contentType, data) + if err != nil { + printErr("Failed to decode favicon: %s [%s] (%v)", imageURL, imageID, err) recordInvalidImageID(imageID) - return "", false, fmt.Errorf("unsupported image type: %s", contentType) + return "", false, err } if err != nil { @@ -522,6 +508,33 @@ func cleanupCache() { } } +func safeDecodeImage(contentType string, data []byte) (img image.Image, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("image decode panic: %v", r) + } + }() + switch contentType { + case "image/x-icon", "image/vnd.microsoft.icon": + img, err = ico.Decode(bytes.NewReader(data)) + case "image/jpeg": + img, err = jpeg.Decode(bytes.NewReader(data)) + case "image/png": + img, err = png.Decode(bytes.NewReader(data)) + case "image/gif": + img, err = gif.Decode(bytes.NewReader(data)) + case "image/webp": + img, err = webp.Decode(bytes.NewReader(data)) + case "image/bmp": + img, err = bmp.Decode(bytes.NewReader(data)) + case "image/tiff": + img, err = tiff.Decode(bytes.NewReader(data)) + default: + err = fmt.Errorf("unsupported image type: %s", contentType) + } + return +} + // Serve missing.svg func serveMissingImage(w http.ResponseWriter, r *http.Request) { missingImagePath := filepath.Join("static", "images", "missing.svg") diff --git a/favicon.go b/favicon.go index 889b543..cd08682 100644 --- a/favicon.go +++ b/favicon.go @@ -1,16 +1,12 @@ package main import ( - "bytes" "crypto/md5" "crypto/tls" "encoding/base64" "encoding/hex" "fmt" "image" - "image/gif" - "image/jpeg" - "image/png" "io" "net/http" "net/url" @@ -21,10 +17,7 @@ import ( "time" "github.com/chai2010/webp" - "github.com/fyne-io/image/ico" - "golang.org/x/image/bmp" "golang.org/x/image/draw" - "golang.org/x/image/tiff" "golang.org/x/net/html" ) @@ -504,28 +497,9 @@ func cacheFavicon(imageURL, imageID string) (string, bool, error) { } // Decode image - var img image.Image - var err error - switch contentType { - case "image/x-icon", "image/vnd.microsoft.icon": - img, err = ico.Decode(bytes.NewReader(data)) - case "image/jpeg": - img, err = jpeg.Decode(bytes.NewReader(data)) - case "image/png": - img, err = png.Decode(bytes.NewReader(data)) - case "image/gif": - img, err = gif.Decode(bytes.NewReader(data)) - case "image/webp": - img, err = webp.Decode(bytes.NewReader(data)) - case "image/bmp": - img, err = bmp.Decode(bytes.NewReader(data)) - case "image/tiff": - img, err = tiff.Decode(bytes.NewReader(data)) - default: - recordInvalidImageID(imageID) - return "", false, fmt.Errorf("unsupported image type: %s", contentType) - } + img, err := safeDecodeImage(contentType, data) if err != nil { + printErr("Failed to decode favicon: %s [%s] (%v)", imageURL, imageID, err) recordInvalidImageID(imageID) return "", false, err }