Implement fallback images in a similar fashion to watermarks. (#374)

* 220. Implement fallback images in a similar fashion to watermarks.

* 220. Fix error formatting.

* 220. Fixes based on @darthsim's feedback.
This commit is contained in:
Ewan Higgs
2020-04-08 16:32:45 +02:00
committed by GitHub
parent cf6f481d83
commit 21b990d895
3 changed files with 53 additions and 11 deletions

View File

@@ -224,6 +224,10 @@ type config struct {
WatermarkURL string WatermarkURL string
WatermarkOpacity float64 WatermarkOpacity float64
FallbackImageData string
FallbackImagePath string
FallbackImageURL string
NewRelicAppName string NewRelicAppName string
NewRelicKey string NewRelicKey string
@@ -377,6 +381,10 @@ func configure() error {
strEnvConfig(&conf.WatermarkURL, "IMGPROXY_WATERMARK_URL") strEnvConfig(&conf.WatermarkURL, "IMGPROXY_WATERMARK_URL")
floatEnvConfig(&conf.WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY") floatEnvConfig(&conf.WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY")
strEnvConfig(&conf.FallbackImageData, "IMGPROXY_FALLBACK_IMAGE_DATA")
strEnvConfig(&conf.FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH")
strEnvConfig(&conf.FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL")
strEnvConfig(&conf.NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME") strEnvConfig(&conf.NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME")
strEnvConfig(&conf.NewRelicKey, "IMGPROXY_NEW_RELIC_KEY") strEnvConfig(&conf.NewRelicKey, "IMGPROXY_NEW_RELIC_KEY")

View File

@@ -9,35 +9,51 @@ import (
func getWatermarkData() (*imageData, error) { func getWatermarkData() (*imageData, error) {
if len(conf.WatermarkData) > 0 { if len(conf.WatermarkData) > 0 {
return base64WatermarkData(conf.WatermarkData) return base64ImageData(conf.WatermarkData)
} }
if len(conf.WatermarkPath) > 0 { if len(conf.WatermarkPath) > 0 {
return fileWatermarkData(conf.WatermarkPath) return fileImageData(conf.WatermarkPath)
} }
if len(conf.WatermarkURL) > 0 { if len(conf.WatermarkURL) > 0 {
return remoteWatermarkData(conf.WatermarkURL) return remoteImageData(conf.WatermarkURL)
} }
return nil, nil return nil, nil
} }
func base64WatermarkData(encoded string) (*imageData, error) { func getFallbackImageData() (*imageData, error) {
if len(conf.FallbackImageData) > 0 {
return base64ImageData(conf.FallbackImageData)
}
if len(conf.FallbackImagePath) > 0 {
return fileImageData(conf.FallbackImagePath)
}
if len(conf.FallbackImageURL) > 0 {
return remoteImageData(conf.FallbackImageURL)
}
return nil, nil
}
func base64ImageData(encoded string) (*imageData, error) {
data, err := base64.StdEncoding.DecodeString(encoded) data, err := base64.StdEncoding.DecodeString(encoded)
if err != nil { if err != nil {
return nil, fmt.Errorf("Can't decode watermark data: %s", err) return nil, fmt.Errorf("Can't decode image data: %s", err)
} }
imgtype, err := checkTypeAndDimensions(bytes.NewReader(data)) imgtype, err := checkTypeAndDimensions(bytes.NewReader(data))
if err != nil { if err != nil {
return nil, fmt.Errorf("Can't decode watermark: %s", err) return nil, fmt.Errorf("Can't decode image: %s", err)
} }
return &imageData{Data: data, Type: imgtype}, nil return &imageData{Data: data, Type: imgtype}, nil
} }
func fileWatermarkData(path string) (*imageData, error) { func fileImageData(path string) (*imageData, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, fmt.Errorf("Can't read watermark: %s", err) return nil, fmt.Errorf("Can't read watermark: %s", err)
@@ -56,18 +72,18 @@ func fileWatermarkData(path string) (*imageData, error) {
return imgdata, err return imgdata, err
} }
func remoteWatermarkData(imageURL string) (*imageData, error) { func remoteImageData(imageURL string) (*imageData, error) {
res, err := requestImage(imageURL) res, err := requestImage(imageURL)
if res != nil { if res != nil {
defer res.Body.Close() defer res.Body.Close()
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("Can't download watermark: %s", err) return nil, fmt.Errorf("Can't download image: %s", err)
} }
imgdata, err := readAndCheckImage(res.Body, int(res.ContentLength)) imgdata, err := readAndCheckImage(res.Body, int(res.ContentLength))
if err != nil { if err != nil {
return nil, fmt.Errorf("Can't download watermark: %s", err) return nil, fmt.Errorf("Can't download image: %s", err)
} }
return imgdata, err return imgdata, err

View File

@@ -16,6 +16,7 @@ var (
processingSem chan struct{} processingSem chan struct{}
headerVaryValue string headerVaryValue string
fallback *imageData
) )
func initProcessingHandler() error { func initProcessingHandler() error {
@@ -45,6 +46,10 @@ func initProcessingHandler() error {
headerVaryValue = strings.Join(vary, ", ") headerVaryValue = strings.Join(vary, ", ")
if err := loadFallback(); err != nil {
return err
}
return nil return nil
} }
@@ -153,7 +158,12 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
if prometheusEnabled { if prometheusEnabled {
incrementPrometheusErrorsTotal("download") incrementPrometheusErrorsTotal("download")
} }
panic(err) if fallback != nil {
logError("Could not load image. Using fallback image: %s", err.Error())
ctx = context.WithValue(ctx, imageDataCtxKey, fallback)
} else {
panic(err)
}
} }
checkTimeout(ctx) checkTimeout(ctx)
@@ -186,3 +196,11 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
respondWithImage(ctx, reqID, r, rw, imageData) 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
}