mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/http: skip content-type sniffing if the header is explicitly unset.
Fixes #5953 R=dsymonds, bradfitz, rsc CC=golang-dev https://golang.org/cl/14434044
This commit is contained in:
parent
51c0d7c0a7
commit
21e6b90d36
4 changed files with 34 additions and 10 deletions
|
|
@ -140,9 +140,11 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
|
||||||
|
|
||||||
code := StatusOK
|
code := StatusOK
|
||||||
|
|
||||||
// If Content-Type isn't set, use the file's extension to find it.
|
// If Content-Type isn't set, use the file's extension to find it, but
|
||||||
ctype := w.Header().Get("Content-Type")
|
// if the Content-Type is unset explicitly, do not sniff the type.
|
||||||
if ctype == "" {
|
ctypes, haveType := w.Header()["Content-Type"]
|
||||||
|
var ctype string
|
||||||
|
if !haveType {
|
||||||
ctype = mime.TypeByExtension(filepath.Ext(name))
|
ctype = mime.TypeByExtension(filepath.Ext(name))
|
||||||
if ctype == "" {
|
if ctype == "" {
|
||||||
// read a chunk to decide between utf-8 text and binary
|
// 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)
|
w.Header().Set("Content-Type", ctype)
|
||||||
|
} else if len(ctypes) > 0 {
|
||||||
|
ctype = ctypes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := sizeFunc()
|
size, err := sizeFunc()
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -319,24 +320,29 @@ func TestServeFileContentType(t *testing.T) {
|
||||||
defer afterTest(t)
|
defer afterTest(t)
|
||||||
const ctype = "icecream/chocolate"
|
const ctype = "icecream/chocolate"
|
||||||
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
|
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)
|
w.Header().Set("Content-Type", ctype)
|
||||||
|
case "2":
|
||||||
|
// Explicitly inhibit sniffing.
|
||||||
|
w.Header()["Content-Type"] = []string{}
|
||||||
}
|
}
|
||||||
ServeFile(w, r, "testdata/file")
|
ServeFile(w, r, "testdata/file")
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
get := func(override, want string) {
|
get := func(override string, want []string) {
|
||||||
resp, err := Get(ts.URL + "?override=" + override)
|
resp, err := Get(ts.URL + "?override=" + override)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if h := resp.Header.Get("Content-Type"); h != want {
|
if h := resp.Header["Content-Type"]; !reflect.DeepEqual(h, want) {
|
||||||
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
|
t.Errorf("Content-Type mismatch: got %v, want %v", h, want)
|
||||||
}
|
}
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
get("0", "text/plain; charset=utf-8")
|
get("0", []string{"text/plain; charset=utf-8"})
|
||||||
get("1", ctype)
|
get("1", []string{ctype})
|
||||||
|
get("2", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServeFileMimeType(t *testing.T) {
|
func TestServeFileMimeType(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -614,3 +614,16 @@ func TestResponseContentLengthShortBody(t *testing.T) {
|
||||||
t.Errorf("io.Copy error = %#v; want io.ErrUnexpectedEOF", err)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,8 @@ func (w *response) requestTooLarge() {
|
||||||
|
|
||||||
// needsSniff reports whether a Content-Type still needs to be sniffed.
|
// needsSniff reports whether a Content-Type still needs to be sniffed.
|
||||||
func (w *response) needsSniff() bool {
|
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
|
// writerOnly hides an io.Writer value's optional ReadFrom method
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue