diff --git a/http/httpguts/guts.go b/http/httpguts/guts.go index 8255fd49..e6cd0ced 100644 --- a/http/httpguts/guts.go +++ b/http/httpguts/guts.go @@ -14,21 +14,6 @@ import ( "strings" ) -// SniffedContentType reports whether ct is a Content-Type that is known -// to cause client-side content sniffing. -// -// This provides just a partial implementation of mime.ParseMediaType -// with the assumption that the Content-Type is not attacker controlled. -func SniffedContentType(ct string) bool { - if i := strings.Index(ct, ";"); i != -1 { - ct = ct[:i] - } - ct = strings.ToLower(strings.TrimSpace(ct)) - return ct == "text/plain" || ct == "application/octet-stream" || - ct == "application/unknown" || ct == "unknown/unknown" || ct == "*/*" || - !strings.Contains(ct, "/") -} - // ValidTrailerHeader reports whether name is a valid header field name to appear // in trailers. // See RFC 7230, Section 4.1.2 diff --git a/http2/server.go b/http2/server.go index acf3b241..769c0fe5 100644 --- a/http2/server.go +++ b/http2/server.go @@ -2312,7 +2312,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { isHeadResp := rws.req.Method == "HEAD" if !rws.sentHeader { rws.sentHeader = true - var ctype, clen string if clen = rws.snapHeader.Get("Content-Length"); clen != "" { rws.snapHeader.Del("Content-Length") @@ -2326,7 +2325,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) { clen = strconv.Itoa(len(p)) } - _, hasContentType := rws.snapHeader["Content-Type"] if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 { if cto := rws.snapHeader.Get("X-Content-Type-Options"); strings.EqualFold("nosniff", cto) { @@ -2339,20 +2337,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { ctype = http.DetectContentType(p) } } - - var noSniff bool - if bodyAllowedForStatus(rws.status) && (rws.sentContentLen > 0 || len(p) > 0) { - // If the content type triggers client-side sniffing on old browsers, - // attach a X-Content-Type-Options header if not present (or explicitly nil). - if _, ok := rws.snapHeader["X-Content-Type-Options"]; !ok { - if hasContentType { - noSniff = httpguts.SniffedContentType(rws.snapHeader.Get("Content-Type")) - } else if ctype != "" { - noSniff = httpguts.SniffedContentType(ctype) - } - } - } - var date string if _, ok := rws.snapHeader["Date"]; !ok { // TODO(bradfitz): be faster here, like net/http? measure. @@ -2371,7 +2355,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { endStream: endStream, contentType: ctype, contentLength: clen, - noSniff: noSniff, date: date, }) if err != nil { diff --git a/http2/server_test.go b/http2/server_test.go index ffa40c0d..baab0f14 100644 --- a/http2/server_test.go +++ b/http2/server_test.go @@ -1810,7 +1810,6 @@ func TestServer_Response_TransferEncoding_chunked(t *testing.T) { {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", strconv.Itoa(len(msg))}, - {"x-content-type-options", "nosniff"}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) @@ -1999,7 +1998,6 @@ func TestServer_Response_LargeWrite(t *testing.T) { wanth := [][2]string{ {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, // sniffed - {"x-content-type-options", "nosniff"}, // and no content-length } if !reflect.DeepEqual(goth, wanth) { @@ -2214,7 +2212,6 @@ func TestServer_Response_Automatic100Continue(t *testing.T) { {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", strconv.Itoa(len(reply))}, - {"x-content-type-options", "nosniff"}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) @@ -2938,7 +2935,6 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) { {"trailer", "Transfer-Encoding, Content-Length, Trailer"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", "5"}, - {"x-content-type-options", "nosniff"}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) @@ -3330,7 +3326,6 @@ func TestServerNoDuplicateContentType(t *testing.T) { {":status", "200"}, {"content-type", ""}, {"content-length", "41"}, - {"x-content-type-options", "nosniff"}, } if !reflect.DeepEqual(headers, want) { t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) diff --git a/http2/transport_test.go b/http2/transport_test.go index 636f1557..17c09cab 100644 --- a/http2/transport_test.go +++ b/http2/transport_test.go @@ -145,10 +145,9 @@ func TestTransport(t *testing.T) { t.Errorf("Status = %q; want %q", g, w) } wantHeader := http.Header{ - "Content-Length": []string{"3"}, - "X-Content-Type-Options": []string{"nosniff"}, - "Content-Type": []string{"text/plain; charset=utf-8"}, - "Date": []string{"XXX"}, // see cleanDate + "Content-Length": []string{"3"}, + "Content-Type": []string{"text/plain; charset=utf-8"}, + "Date": []string{"XXX"}, // see cleanDate } cleanDate(res) if !reflect.DeepEqual(res.Header, wantHeader) { diff --git a/http2/write.go b/http2/write.go index a5120412..8a9711f6 100644 --- a/http2/write.go +++ b/http2/write.go @@ -186,7 +186,6 @@ type writeResHeaders struct { date string contentType string contentLength string - noSniff bool } func encKV(enc *hpack.Encoder, k, v string) { @@ -223,9 +222,6 @@ func (w *writeResHeaders) writeFrame(ctx writeContext) error { if w.contentLength != "" { encKV(enc, "content-length", w.contentLength) } - if w.noSniff { - encKV(enc, "x-content-type-options", "nosniff") - } if w.date != "" { encKV(enc, "date", w.date) }