1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
20 var sniffTests
= []struct {
26 {"Empty", []byte{}, "text/plain; charset=utf-8"},
27 {"Binary", []byte{1, 2, 3}, "application/octet-stream"},
29 {"HTML document #1", []byte(`<HtMl><bOdY>blah blah blah</body></html>`), "text/html; charset=utf-8"},
30 {"HTML document #2", []byte(`<HTML></HTML>`), "text/html; charset=utf-8"},
31 {"HTML document #3 (leading whitespace)", []byte(` <!DOCTYPE HTML>...`), "text/html; charset=utf-8"},
32 {"HTML document #4 (leading CRLF)", []byte("\r\n<html>..."), "text/html; charset=utf-8"},
34 {"Plain text", []byte(`This is not HTML. It has ☃ though.`), "text/plain; charset=utf-8"},
36 {"XML", []byte("\n<?xml!"), "text/xml; charset=utf-8"},
39 {"GIF 87a", []byte(`GIF87a`), "image/gif"},
40 {"GIF 89a", []byte(`GIF89a...`), "image/gif"},
43 {"MIDI audio", []byte("MThd\x00\x00\x00\x06\x00\x01"), "audio/midi"},
44 {"MP3 audio/MPEG audio", []byte("ID3\x03\x00\x00\x00\x00\x0f"), "audio/mpeg"},
45 {"WAV audio #1", []byte("RIFFb\xb8\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
46 {"WAV audio #2", []byte("RIFF,\x00\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
47 {"AIFF audio #1", []byte("FORM\x00\x00\x00\x00AIFFCOMM\x00\x00\x00\x12\x00\x01\x00\x00\x57\x55\x00\x10\x40\x0d\xf3\x34"), "audio/aiff"},
49 {"OGG audio", []byte("OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x7e\x46\x00\x00\x00\x00\x00\x00\x1f\xf6\xb4\xfc\x01\x1e\x01\x76\x6f\x72"), "application/ogg"},
50 {"Must not match OGG", []byte("owow\x00"), "application/octet-stream"},
51 {"Must not match OGG", []byte("oooS\x00"), "application/octet-stream"},
52 {"Must not match OGG", []byte("oggS\x00"), "application/octet-stream"},
55 {"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
56 {"AVI video #1", []byte("RIFF,O\n\x00AVI LISTÀ"), "video/avi"},
57 {"AVI video #2", []byte("RIFF,\n\x00\x00AVI LISTÀ"), "video/avi"},
60 // {"MS.FontObject", []byte("\x00\x00")},
61 {"TTF sample I", []byte("\x00\x01\x00\x00\x00\x17\x01\x00\x00\x04\x01\x60\x4f"), "font/ttf"},
62 {"TTF sample II", []byte("\x00\x01\x00\x00\x00\x0e\x00\x80\x00\x03\x00\x60\x46"), "font/ttf"},
64 {"OTTO sample I", []byte("\x4f\x54\x54\x4f\x00\x0e\x00\x80\x00\x03\x00\x60\x42\x41\x53\x45"), "font/otf"},
66 {"woff sample I", []byte("\x77\x4f\x46\x46\x00\x01\x00\x00\x00\x00\x30\x54\x00\x0d\x00\x00"), "font/woff"},
67 {"woff2 sample", []byte("\x77\x4f\x46\x32\x00\x01\x00\x00\x00"), "font/woff2"},
68 {"wasm sample", []byte("\x00\x61\x73\x6d\x01\x00"), "application/wasm"},
71 func TestDetectContentType(t
*testing
.T
) {
72 for _
, tt
:= range sniffTests
{
73 ct
:= DetectContentType(tt
.data
)
74 if ct
!= tt
.contentType
{
75 t
.Errorf("%v: DetectContentType = %q, want %q", tt
.desc
, ct
, tt
.contentType
)
80 func TestServerContentType_h1(t
*testing
.T
) { testServerContentType(t
, h1Mode
) }
81 func TestServerContentType_h2(t
*testing
.T
) { testServerContentType(t
, h2Mode
) }
83 func testServerContentType(t
*testing
.T
, h2
bool) {
86 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
87 i
, _
:= strconv
.Atoi(r
.FormValue("i"))
89 n
, err
:= w
.Write(tt
.data
)
90 if n
!= len(tt
.data
) || err
!= nil {
91 log
.Fatalf("%v: Write(%q) = %v, %v want %d, nil", tt
.desc
, tt
.data
, n
, err
, len(tt
.data
))
96 for i
, tt
:= range sniffTests
{
97 resp
, err
:= cst
.c
.Get(cst
.ts
.URL
+ "/?i=" + strconv
.Itoa(i
))
99 t
.Errorf("%v: %v", tt
.desc
, err
)
102 // DetectContentType is defined to return
103 // text/plain; charset=utf-8 for an empty body,
104 // but as of Go 1.10 the HTTP server has been changed
105 // to return no content-type at all for an empty body.
106 // Adjust the expectation here.
107 wantContentType
:= tt
.contentType
108 if len(tt
.data
) == 0 {
111 if ct
:= resp
.Header
.Get("Content-Type"); ct
!= wantContentType
{
112 t
.Errorf("%v: Content-Type = %q, want %q", tt
.desc
, ct
, wantContentType
)
114 data
, err
:= ioutil
.ReadAll(resp
.Body
)
116 t
.Errorf("%v: reading body: %v", tt
.desc
, err
)
117 } else if !bytes
.Equal(data
, tt
.data
) {
118 t
.Errorf("%v: data is %q, want %q", tt
.desc
, data
, tt
.data
)
124 // Issue 5953: shouldn't sniff if the handler set a Content-Type header,
125 // even if it's the empty string.
126 func TestServerIssue5953_h1(t
*testing
.T
) { testServerIssue5953(t
, h1Mode
) }
127 func TestServerIssue5953_h2(t
*testing
.T
) { testServerIssue5953(t
, h2Mode
) }
128 func testServerIssue5953(t
*testing
.T
, h2
bool) {
130 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
131 w
.Header()["Content-Type"] = []string{""}
132 fmt
.Fprintf(w
, "<html><head></head><body>hi</body></html>")
136 resp
, err
:= cst
.c
.Get(cst
.ts
.URL
)
141 got
:= resp
.Header
["Content-Type"]
143 if !reflect
.DeepEqual(got
, want
) {
144 t
.Errorf("Content-Type = %q; want %q", got
, want
)
149 func TestContentTypeWithCopy_h1(t
*testing
.T
) { testContentTypeWithCopy(t
, h1Mode
) }
150 func TestContentTypeWithCopy_h2(t
*testing
.T
) { testContentTypeWithCopy(t
, h2Mode
) }
151 func testContentTypeWithCopy(t
*testing
.T
, h2
bool) {
155 input
= "\n<html>\n\t<head>\n"
156 expected
= "text/html; charset=utf-8"
159 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
160 // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
161 buf
:= bytes
.NewBuffer([]byte(input
))
162 n
, err
:= io
.Copy(w
, buf
)
163 if int(n
) != len(input
) || err
!= nil {
164 t
.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input
, n
, err
, len(input
))
169 resp
, err
:= cst
.c
.Get(cst
.ts
.URL
)
171 t
.Fatalf("Get: %v", err
)
173 if ct
:= resp
.Header
.Get("Content-Type"); ct
!= expected
{
174 t
.Errorf("Content-Type = %q, want %q", ct
, expected
)
176 data
, err
:= ioutil
.ReadAll(resp
.Body
)
178 t
.Errorf("reading body: %v", err
)
179 } else if !bytes
.Equal(data
, []byte(input
)) {
180 t
.Errorf("data is %q, want %q", data
, input
)
185 func TestSniffWriteSize_h1(t
*testing
.T
) { testSniffWriteSize(t
, h1Mode
) }
186 func TestSniffWriteSize_h2(t
*testing
.T
) { testSniffWriteSize(t
, h2Mode
) }
187 func testSniffWriteSize(t
*testing
.T
, h2
bool) {
190 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
191 size
, _
:= strconv
.Atoi(r
.FormValue("size"))
192 written
, err
:= io
.WriteString(w
, strings
.Repeat("a", size
))
194 t
.Errorf("write of %d bytes: %v", size
, err
)
198 t
.Errorf("write of %d bytes wrote %d bytes", size
, written
)
202 for _
, size
:= range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
203 res
, err
:= cst
.c
.Get(fmt
.Sprintf("%s/?size=%d", cst
.ts
.URL
, size
))
205 t
.Fatalf("size %d: %v", size
, err
)
207 if _
, err
:= io
.Copy(ioutil
.Discard
, res
.Body
); err
!= nil {
208 t
.Fatalf("size %d: io.Copy of body = %v", size
, err
)
210 if err
:= res
.Body
.Close(); err
!= nil {
211 t
.Fatalf("size %d: body Close = %v", size
, err
)