浏览代码

Minor changes in fallback images feature; Add docs for fallback images

DarthSim 5 年之前
父节点
当前提交
6c348adb0b
共有 5 个文件被更改,包括 53 次插入44 次删除
  1. 2 0
      CHANGELOG.md
  2. 8 0
      docs/configuration.md
  3. 0 13
      download.go
  4. 30 16
      image_data.go
  5. 13 15
      processing_handler.go

+ 2 - 0
CHANGELOG.md

@@ -1,6 +1,8 @@
 # Changelog
 
 ## [Unreleased]
+### Added
+- Fallback images.
 
 ## [2.12.0] - 2020-04-07
 ### Addded

+ 8 - 0
docs/configuration.md

@@ -155,6 +155,14 @@ imgproxy Pro can extract specific frames of videos to create thumbnails. The fea
 
 Read more about watermarks in the [Watermark](watermark.md) guide.
 
+## Fallback image
+
+You can set up a fallback image that will be used in case imgproxy can't fetch the requested one. Use one of the following variables:
+
+* `IMGPROXY_FALLBACK_IMAGE_DATA`: Base64-encoded image data. You can easily calculate it with `base64 tmp/fallback.png | tr -d '\n'`;
+* `IMGPROXY_FALLBACK_IMAGE_PATH`: path to the locally stored image;
+* `IMGPROXY_FALLBACK_IMAGE_URL`: fallback image URL.
+
 ## Presets
 
 Read about imgproxy presets in the [Presets](presets.md) guide.

+ 0 - 13
download.go

@@ -30,19 +30,6 @@ const msgSourceImageIsUnreachable = "Source image is unreachable"
 
 var downloadBufPool *bufPool
 
-type imageData struct {
-	Data []byte
-	Type imageType
-
-	cancel context.CancelFunc
-}
-
-func (d *imageData) Close() {
-	if d.cancel != nil {
-		d.cancel()
-	}
-}
-
 type limitReader struct {
 	r    io.Reader
 	left int

+ 30 - 16
image_data.go

@@ -2,22 +2,36 @@ package main
 
 import (
 	"bytes"
+	"context"
 	"encoding/base64"
 	"fmt"
 	"os"
 )
 
+type imageData struct {
+	Data []byte
+	Type imageType
+
+	cancel context.CancelFunc
+}
+
+func (d *imageData) Close() {
+	if d.cancel != nil {
+		d.cancel()
+	}
+}
+
 func getWatermarkData() (*imageData, error) {
 	if len(conf.WatermarkData) > 0 {
-		return base64ImageData(conf.WatermarkData)
+		return base64ImageData(conf.WatermarkData, "watermark")
 	}
 
 	if len(conf.WatermarkPath) > 0 {
-		return fileImageData(conf.WatermarkPath)
+		return fileImageData(conf.WatermarkPath, "watermark")
 	}
 
 	if len(conf.WatermarkURL) > 0 {
-		return remoteImageData(conf.WatermarkURL)
+		return remoteImageData(conf.WatermarkURL, "watermark")
 	}
 
 	return nil, nil
@@ -25,65 +39,65 @@ func getWatermarkData() (*imageData, error) {
 
 func getFallbackImageData() (*imageData, error) {
 	if len(conf.FallbackImageData) > 0 {
-		return base64ImageData(conf.FallbackImageData)
+		return base64ImageData(conf.FallbackImageData, "fallback image")
 	}
 
 	if len(conf.FallbackImagePath) > 0 {
-		return fileImageData(conf.FallbackImagePath)
+		return fileImageData(conf.FallbackImagePath, "fallback image")
 	}
 
 	if len(conf.FallbackImageURL) > 0 {
-		return remoteImageData(conf.FallbackImageURL)
+		return remoteImageData(conf.FallbackImageURL, "fallback image")
 	}
 
 	return nil, nil
 }
 
-func base64ImageData(encoded string) (*imageData, error) {
+func base64ImageData(encoded, desc string) (*imageData, error) {
 	data, err := base64.StdEncoding.DecodeString(encoded)
 	if err != nil {
-		return nil, fmt.Errorf("Can't decode image data: %s", err)
+		return nil, fmt.Errorf("Can't decode %s data: %s", desc, err)
 	}
 
 	imgtype, err := checkTypeAndDimensions(bytes.NewReader(data))
 	if err != nil {
-		return nil, fmt.Errorf("Can't decode image: %s", err)
+		return nil, fmt.Errorf("Can't decode %s: %s", desc, err)
 	}
 
 	return &imageData{Data: data, Type: imgtype}, nil
 }
 
-func fileImageData(path string) (*imageData, error) {
+func fileImageData(path, desc string) (*imageData, error) {
 	f, err := os.Open(path)
 	if err != nil {
-		return nil, fmt.Errorf("Can't read watermark: %s", err)
+		return nil, fmt.Errorf("Can't read %s: %s", desc, err)
 	}
 
 	fi, err := f.Stat()
 	if err != nil {
-		return nil, fmt.Errorf("Can't read watermark: %s", err)
+		return nil, fmt.Errorf("Can't read %s: %s", desc, err)
 	}
 
 	imgdata, err := readAndCheckImage(f, int(fi.Size()))
 	if err != nil {
-		return nil, fmt.Errorf("Can't read watermark: %s", err)
+		return nil, fmt.Errorf("Can't read %s: %s", desc, err)
 	}
 
 	return imgdata, err
 }
 
-func remoteImageData(imageURL string) (*imageData, error) {
+func remoteImageData(imageURL, desc string) (*imageData, error) {
 	res, err := requestImage(imageURL)
 	if res != nil {
 		defer res.Body.Close()
 	}
 	if err != nil {
-		return nil, fmt.Errorf("Can't download image: %s", err)
+		return nil, fmt.Errorf("Can't download %s: %s", desc, err)
 	}
 
 	imgdata, err := readAndCheckImage(res.Body, int(res.ContentLength))
 	if err != nil {
-		return nil, fmt.Errorf("Can't download image: %s", err)
+		return nil, fmt.Errorf("Can't download %s: %s", desc, err)
 	}
 
 	return imgdata, err

+ 13 - 15
processing_handler.go

@@ -16,14 +16,15 @@ var (
 	processingSem chan struct{}
 
 	headerVaryValue string
-	fallback        *imageData
+	fallbackImage   *imageData
 )
 
 func initProcessingHandler() error {
+	var err error
+
 	processingSem = make(chan struct{}, conf.Concurrency)
 
 	if conf.GZipCompression > 0 {
-		var err error
 		responseGzipBufPool = newBufPool("gzip", conf.Concurrency, conf.GZipBufferSize)
 		if responseGzipPool, err = newGzipPool(conf.Concurrency); err != nil {
 			return err
@@ -46,7 +47,7 @@ func initProcessingHandler() error {
 
 	headerVaryValue = strings.Join(vary, ", ")
 
-	if err := loadFallback(); err != nil {
+	if fallbackImage, err = getFallbackImageData(); err != nil {
 		return err
 	}
 
@@ -158,12 +159,17 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
 		if prometheusEnabled {
 			incrementPrometheusErrorsTotal("download")
 		}
-		if fallback != nil {
-			logError("Could not load image. Using fallback image: %s", err.Error())
-			ctx = context.WithValue(ctx, imageDataCtxKey, fallback)
-		} else {
+
+		if fallbackImage == nil {
 			panic(err)
 		}
+
+		if ierr, ok := err.(*imgproxyError); !ok || ierr.Unexpected {
+			reportError(err, r)
+		}
+
+		logWarning("Could not load image. Using fallback image: %s", err.Error())
+		ctx = context.WithValue(ctx, imageDataCtxKey, fallbackImage)
 	}
 
 	checkTimeout(ctx)
@@ -196,11 +202,3 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
 
 	respondWithImage(ctx, reqID, r, rw, imageData)
 }
-
-func loadFallback() (err error) {
-	fallback, err = getFallbackImageData()
-	if err != nil {
-		logError("Could not load fallback data. Fallback images will not be available: %s", err.Error())
-	}
-	return err
-}