From 04871c8b7fd4cf596371552b22d1e02b5d35f9fe Mon Sep 17 00:00:00 2001 From: DarthSim Date: Thu, 26 Apr 2018 17:22:31 +0600 Subject: [PATCH] Add CORS headers --- README.md | 1 + config.go | 4 ++++ errors.go | 1 + server.go | 27 +++++++++++++++++++++++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ceeaddcb..8d8ee07c 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ $ xxd -g 2 -l 64 -p /dev/random | tr -d '\n' imgproxy protects you from so-called image bombs. Here is how you can specify maximum image dimensions and resolution which you consider reasonable: +* `IMGPROXY_ALLOW_ORIGIN` - when set, enables CORS headers with provided origin. CORS headers are disabled by default. * `IMGPROXY_MAX_SRC_DIMENSION` — the maximum dimensions of the source image, in pixels, for both width and height. Images with larger real size will be rejected. Default: `8192`; * `IMGPROXY_MAX_SRC_RESOLUTION` — the maximum resolution of the source image, in megapixels. Images with larger real size will be rejected. Default: `16.8`; diff --git a/config.go b/config.go index bc28b835..a1dbfabd 100644 --- a/config.go +++ b/config.go @@ -95,6 +95,8 @@ type config struct { Secret string + AllowOrigin string + LocalFileSystemRoot string ETagEnabled bool @@ -147,6 +149,8 @@ func init() { strEnvConfig(&conf.Secret, "IMGPROXY_SECRET") + strEnvConfig(&conf.AllowOrigin, "IMGPROXY_ALLOW_ORIGIN") + strEnvConfig(&conf.LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT") boolEnvConfig(&conf.ETagEnabled, "IMGPROXY_USE_ETAG") diff --git a/errors.go b/errors.go index 1158f783..af319428 100644 --- a/errors.go +++ b/errors.go @@ -27,6 +27,7 @@ func newUnexpectedError(err error, skip int) imgproxyError { var ( invalidSecretErr = newError(403, "Invalid secret", "Forbidden") + invalidMethodErr = newError(422, "Invalid request method", "Method doesn't allowed") ) func stacktrace(skip int) string { diff --git a/server.go b/server.go index c8aadf7f..a679997d 100644 --- a/server.go +++ b/server.go @@ -105,6 +105,13 @@ func logResponse(status int, msg string) { log.Printf("|\033[7;%dm %d \033[0m| %s\n", color, status, msg) } +func writeCORS(rw http.ResponseWriter) { + if len(conf.AllowOrigin) > 0 { + rw.Header().Set("Access-Control-Allow-Origin", conf.AllowOrigin) + rw.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONs") + } +} + func respondWithImage(reqID string, r *http.Request, rw http.ResponseWriter, data []byte, imgURL string, po processingOptions, duration time.Duration) { gzipped := strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") && conf.GZipCompression > 0 @@ -136,6 +143,11 @@ func respondWithError(reqID string, rw http.ResponseWriter, err imgproxyError) { rw.Write([]byte(err.PublicMessage)) } +func respondWithOptions(reqID string, rw http.ResponseWriter) { + logResponse(200, fmt.Sprintf("[%s] Respond with options", reqID)) + rw.WriteHeader(200) +} + func checkSecret(s string) bool { if len(conf.Secret) == 0 { return true @@ -154,8 +166,6 @@ func (h *httpHandler) unlock() { func (h *httpHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { reqID, _ := nanoid.Nanoid() - log.Printf("[%s] GET: %s\n", reqID, r.URL.RequestURI()) - defer func() { if r := recover(); r != nil { if err, ok := r.(imgproxyError); ok { @@ -166,6 +176,19 @@ func (h *httpHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { } }() + log.Printf("[%s] %s: %s\n", reqID, r.Method, r.URL.RequestURI()) + + writeCORS(rw) + + if r.Method == http.MethodOptions { + respondWithOptions(reqID, rw) + return + } + + if r.Method != http.MethodGet { + panic(invalidMethodErr) + } + if !checkSecret(r.Header.Get("Authorization")) { panic(invalidSecretErr) }