From cf54b2cf2c9ea55559d8532af5d2db2f4c4cd3ad Mon Sep 17 00:00:00 2001 From: Will Norris Date: Tue, 26 Mar 2019 16:38:37 +0000 Subject: [PATCH] detect content type if response header is missing Some misconfigured servers will fail to properly set the content-type in the response header. In those cases, detect the content-type from the response body. Refs #132 --- imageproxy.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/imageproxy.go b/imageproxy.go index 9ba81b8..61a3961 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -170,6 +170,7 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { http.Error(w, msg, http.StatusInternalServerError) return } + // close the original resp.Body, even if we wrap it in a NopCloser below defer resp.Body.Close() cached := resp.Header.Get(httpcache.XFromCache) @@ -185,6 +186,12 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { } contentType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if contentType == "" { + // try to detect content type + b := bufio.NewReader(resp.Body) + resp.Body = ioutil.NopCloser(b) + contentType = peekContentType(b) + } if resp.ContentLength != 0 && !contentTypeMatches(p.ContentTypes, contentType) { log.Printf("content-type not allowed: %q", contentType) http.Error(w, msgNotAllowed, http.StatusForbidden) @@ -201,6 +208,16 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { io.Copy(w, resp.Body) } +// peekContentType peeks at the first 512 bytes of p, and attempts to detect +// the content type. Returns empty string if error occurs. +func peekContentType(p *bufio.Reader) string { + byt, err := p.Peek(512) + if err != nil && err != bufio.ErrBufferFull { + return "" + } + return http.DetectContentType(byt) +} + // copyHeader copies header values from src to dst, adding to any existing // values with the same header name. If keys is not empty, only those header // keys will be copied.