diff --git a/config.go b/config.go index dd95e20b..9bc86218 100644 --- a/config.go +++ b/config.go @@ -224,6 +224,10 @@ type config struct { WatermarkURL string WatermarkOpacity float64 + FallbackImageData string + FallbackImagePath string + FallbackImageURL string + NewRelicAppName string NewRelicKey string @@ -377,6 +381,10 @@ func configure() error { strEnvConfig(&conf.WatermarkURL, "IMGPROXY_WATERMARK_URL") 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.NewRelicKey, "IMGPROXY_NEW_RELIC_KEY") diff --git a/watermark_data.go b/image_data.go similarity index 54% rename from watermark_data.go rename to image_data.go index 4716733a..01bab47e 100644 --- a/watermark_data.go +++ b/image_data.go @@ -9,35 +9,51 @@ import ( func getWatermarkData() (*imageData, error) { if len(conf.WatermarkData) > 0 { - return base64WatermarkData(conf.WatermarkData) + return base64ImageData(conf.WatermarkData) } if len(conf.WatermarkPath) > 0 { - return fileWatermarkData(conf.WatermarkPath) + return fileImageData(conf.WatermarkPath) } if len(conf.WatermarkURL) > 0 { - return remoteWatermarkData(conf.WatermarkURL) + return remoteImageData(conf.WatermarkURL) } 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) 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)) 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 } -func fileWatermarkData(path string) (*imageData, error) { +func fileImageData(path string) (*imageData, error) { f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("Can't read watermark: %s", err) @@ -56,18 +72,18 @@ func fileWatermarkData(path string) (*imageData, error) { return imgdata, err } -func remoteWatermarkData(imageURL string) (*imageData, error) { +func remoteImageData(imageURL string) (*imageData, error) { res, err := requestImage(imageURL) if res != nil { defer res.Body.Close() } 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)) 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 diff --git a/processing_handler.go b/processing_handler.go index b14cc8bb..4a7c55ca 100644 --- a/processing_handler.go +++ b/processing_handler.go @@ -16,6 +16,7 @@ var ( processingSem chan struct{} headerVaryValue string + fallback *imageData ) func initProcessingHandler() error { @@ -45,6 +46,10 @@ func initProcessingHandler() error { headerVaryValue = strings.Join(vary, ", ") + if err := loadFallback(); err != nil { + return err + } + return nil } @@ -153,7 +158,12 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) { if prometheusEnabled { 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) @@ -186,3 +196,11 @@ 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 +}