]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: skip content-type sniffing if the header is explicitly unset.
authorMichael Piatek <piatek@google.com>
Mon, 14 Oct 2013 21:22:04 +0000 (08:22 +1100)
committerDavid Symonds <dsymonds@golang.org>
Mon, 14 Oct 2013 21:22:04 +0000 (08:22 +1100)
Fixes #5953

R=dsymonds, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/14434044

src/pkg/net/http/fs.go
src/pkg/net/http/fs_test.go
src/pkg/net/http/response_test.go
src/pkg/net/http/server.go

index e7bcefed15dfc5d20d214759f9b624d4572350ef..8b32ca1d0eaf4652d4bbf649657a793124458c68 100644 (file)
@@ -140,9 +140,11 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 
        code := StatusOK
 
-       // If Content-Type isn't set, use the file's extension to find it.
-       ctype := w.Header().Get("Content-Type")
-       if ctype == "" {
+       // If Content-Type isn't set, use the file's extension to find it, but
+       // if the Content-Type is unset explicitly, do not sniff the type.
+       ctypes, haveType := w.Header()["Content-Type"]
+       var ctype string
+       if !haveType {
                ctype = mime.TypeByExtension(filepath.Ext(name))
                if ctype == "" {
                        // read a chunk to decide between utf-8 text and binary
@@ -156,6 +158,8 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
                        }
                }
                w.Header().Set("Content-Type", ctype)
+       } else if len(ctypes) > 0 {
+               ctype = ctypes[0]
        }
 
        size, err := sizeFunc()
index 125d8b438dcc06f2aa617cc3727697685eef4b7f..ae54edf0cf504fc9d80414a2a0246155ce078b78 100644 (file)
@@ -20,6 +20,7 @@ import (
        "os/exec"
        "path"
        "path/filepath"
+       "reflect"
        "regexp"
        "runtime"
        "strconv"
@@ -319,24 +320,29 @@ func TestServeFileContentType(t *testing.T) {
        defer afterTest(t)
        const ctype = "icecream/chocolate"
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-               if r.FormValue("override") == "1" {
+               switch r.FormValue("override") {
+               case "1":
                        w.Header().Set("Content-Type", ctype)
+               case "2":
+                       // Explicitly inhibit sniffing.
+                       w.Header()["Content-Type"] = []string{}
                }
                ServeFile(w, r, "testdata/file")
        }))
        defer ts.Close()
-       get := func(override, want string) {
+       get := func(override string, want []string) {
                resp, err := Get(ts.URL + "?override=" + override)
                if err != nil {
                        t.Fatal(err)
                }
-               if h := resp.Header.Get("Content-Type"); h != want {
-                       t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
+               if h := resp.Header["Content-Type"]; !reflect.DeepEqual(h, want) {
+                       t.Errorf("Content-Type mismatch: got %v, want %v", h, want)
                }
                resp.Body.Close()
        }
-       get("0", "text/plain; charset=utf-8")
-       get("1", ctype)
+       get("0", []string{"text/plain; charset=utf-8"})
+       get("1", []string{ctype})
+       get("2", nil)
 }
 
 func TestServeFileMimeType(t *testing.T) {
index 181937a7826e2f7feb1150f56b22f8aa20d8cb9b..5044306a876cb1022a26c6051e29fd306f5434ce 100644 (file)
@@ -614,3 +614,16 @@ func TestResponseContentLengthShortBody(t *testing.T) {
                t.Errorf("io.Copy error = %#v; want io.ErrUnexpectedEOF", err)
        }
 }
+
+func TestNeedsSniff(t *testing.T) {
+       // needsSniff returns true with an empty response.
+       r := &response{}
+       if got, want := r.needsSniff(), true; got != want {
+               t.Errorf("needsSniff = %t; want %t", got, want)
+       }
+       // needsSniff returns false when Content-Type = nil.
+       r.handlerHeader = Header{"Content-Type": nil}
+       if got, want := r.needsSniff(), false; got != want {
+               t.Errorf("needsSniff empty Content-Type = %t; want %t", got, want)
+       }
+}
index cc0b4e237b0d263f2015df1276c6c756225faafc..0e46863d5aee051b39c53d0c6d60e5606641b73e 100644 (file)
@@ -341,7 +341,8 @@ func (w *response) requestTooLarge() {
 
 // needsSniff reports whether a Content-Type still needs to be sniffed.
 func (w *response) needsSniff() bool {
-       return !w.cw.wroteHeader && w.handlerHeader.Get("Content-Type") == "" && w.written < sniffLen
+       _, haveType := w.handlerHeader["Content-Type"]
+       return !w.cw.wroteHeader && !haveType && w.written < sniffLen
 }
 
 // writerOnly hides an io.Writer value's optional ReadFrom method