Home | History | Annotate | Download | only in http
      1 // Copyright 2009 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.
      4 
      5 package http_test
      6 
      7 import (
      8 	"bufio"
      9 	"bytes"
     10 	"encoding/base64"
     11 	"fmt"
     12 	"io"
     13 	"io/ioutil"
     14 	"mime/multipart"
     15 	. "net/http"
     16 	"net/http/httptest"
     17 	"net/url"
     18 	"os"
     19 	"reflect"
     20 	"regexp"
     21 	"strings"
     22 	"testing"
     23 )
     24 
     25 func TestQuery(t *testing.T) {
     26 	req := &Request{Method: "GET"}
     27 	req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
     28 	if q := req.FormValue("q"); q != "foo" {
     29 		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
     30 	}
     31 }
     32 
     33 func TestPostQuery(t *testing.T) {
     34 	req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
     35 		strings.NewReader("z=post&both=y&prio=2&empty="))
     36 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
     37 
     38 	if q := req.FormValue("q"); q != "foo" {
     39 		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
     40 	}
     41 	if z := req.FormValue("z"); z != "post" {
     42 		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
     43 	}
     44 	if bq, found := req.PostForm["q"]; found {
     45 		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
     46 	}
     47 	if bz := req.PostFormValue("z"); bz != "post" {
     48 		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
     49 	}
     50 	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
     51 		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
     52 	}
     53 	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
     54 		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
     55 	}
     56 	if prio := req.FormValue("prio"); prio != "2" {
     57 		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
     58 	}
     59 	if empty := req.FormValue("empty"); empty != "" {
     60 		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
     61 	}
     62 }
     63 
     64 func TestPatchQuery(t *testing.T) {
     65 	req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
     66 		strings.NewReader("z=post&both=y&prio=2&empty="))
     67 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
     68 
     69 	if q := req.FormValue("q"); q != "foo" {
     70 		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
     71 	}
     72 	if z := req.FormValue("z"); z != "post" {
     73 		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
     74 	}
     75 	if bq, found := req.PostForm["q"]; found {
     76 		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
     77 	}
     78 	if bz := req.PostFormValue("z"); bz != "post" {
     79 		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
     80 	}
     81 	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
     82 		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
     83 	}
     84 	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
     85 		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
     86 	}
     87 	if prio := req.FormValue("prio"); prio != "2" {
     88 		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
     89 	}
     90 	if empty := req.FormValue("empty"); empty != "" {
     91 		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
     92 	}
     93 }
     94 
     95 type stringMap map[string][]string
     96 type parseContentTypeTest struct {
     97 	shouldError bool
     98 	contentType stringMap
     99 }
    100 
    101 var parseContentTypeTests = []parseContentTypeTest{
    102 	{false, stringMap{"Content-Type": {"text/plain"}}},
    103 	// Empty content type is legal - shoult be treated as
    104 	// application/octet-stream (RFC 2616, section 7.2.1)
    105 	{false, stringMap{}},
    106 	{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
    107 	{false, stringMap{"Content-Type": {"application/unknown"}}},
    108 }
    109 
    110 func TestParseFormUnknownContentType(t *testing.T) {
    111 	for i, test := range parseContentTypeTests {
    112 		req := &Request{
    113 			Method: "POST",
    114 			Header: Header(test.contentType),
    115 			Body:   ioutil.NopCloser(strings.NewReader("body")),
    116 		}
    117 		err := req.ParseForm()
    118 		switch {
    119 		case err == nil && test.shouldError:
    120 			t.Errorf("test %d should have returned error", i)
    121 		case err != nil && !test.shouldError:
    122 			t.Errorf("test %d should not have returned error, got %v", i, err)
    123 		}
    124 	}
    125 }
    126 
    127 func TestParseFormInitializeOnError(t *testing.T) {
    128 	nilBody, _ := NewRequest("POST", "http://www.google.com/search?q=foo", nil)
    129 	tests := []*Request{
    130 		nilBody,
    131 		{Method: "GET", URL: nil},
    132 	}
    133 	for i, req := range tests {
    134 		err := req.ParseForm()
    135 		if req.Form == nil {
    136 			t.Errorf("%d. Form not initialized, error %v", i, err)
    137 		}
    138 		if req.PostForm == nil {
    139 			t.Errorf("%d. PostForm not initialized, error %v", i, err)
    140 		}
    141 	}
    142 }
    143 
    144 func TestMultipartReader(t *testing.T) {
    145 	req := &Request{
    146 		Method: "POST",
    147 		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
    148 		Body:   ioutil.NopCloser(new(bytes.Buffer)),
    149 	}
    150 	multipart, err := req.MultipartReader()
    151 	if multipart == nil {
    152 		t.Errorf("expected multipart; error: %v", err)
    153 	}
    154 
    155 	req.Header = Header{"Content-Type": {"text/plain"}}
    156 	multipart, err = req.MultipartReader()
    157 	if multipart != nil {
    158 		t.Error("unexpected multipart for text/plain")
    159 	}
    160 }
    161 
    162 func TestParseMultipartForm(t *testing.T) {
    163 	req := &Request{
    164 		Method: "POST",
    165 		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
    166 		Body:   ioutil.NopCloser(new(bytes.Buffer)),
    167 	}
    168 	err := req.ParseMultipartForm(25)
    169 	if err == nil {
    170 		t.Error("expected multipart EOF, got nil")
    171 	}
    172 
    173 	req.Header = Header{"Content-Type": {"text/plain"}}
    174 	err = req.ParseMultipartForm(25)
    175 	if err != ErrNotMultipart {
    176 		t.Error("expected ErrNotMultipart for text/plain")
    177 	}
    178 }
    179 
    180 func TestRedirect(t *testing.T) {
    181 	defer afterTest(t)
    182 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
    183 		switch r.URL.Path {
    184 		case "/":
    185 			w.Header().Set("Location", "/foo/")
    186 			w.WriteHeader(StatusSeeOther)
    187 		case "/foo/":
    188 			fmt.Fprintf(w, "foo")
    189 		default:
    190 			w.WriteHeader(StatusBadRequest)
    191 		}
    192 	}))
    193 	defer ts.Close()
    194 
    195 	var end = regexp.MustCompile("/foo/$")
    196 	r, err := Get(ts.URL)
    197 	if err != nil {
    198 		t.Fatal(err)
    199 	}
    200 	r.Body.Close()
    201 	url := r.Request.URL.String()
    202 	if r.StatusCode != 200 || !end.MatchString(url) {
    203 		t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
    204 	}
    205 }
    206 
    207 func TestSetBasicAuth(t *testing.T) {
    208 	r, _ := NewRequest("GET", "http://example.com/", nil)
    209 	r.SetBasicAuth("Aladdin", "open sesame")
    210 	if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
    211 		t.Errorf("got header %q, want %q", g, e)
    212 	}
    213 }
    214 
    215 func TestMultipartRequest(t *testing.T) {
    216 	// Test that we can read the values and files of a
    217 	// multipart request with FormValue and FormFile,
    218 	// and that ParseMultipartForm can be called multiple times.
    219 	req := newTestMultipartRequest(t)
    220 	if err := req.ParseMultipartForm(25); err != nil {
    221 		t.Fatal("ParseMultipartForm first call:", err)
    222 	}
    223 	defer req.MultipartForm.RemoveAll()
    224 	validateTestMultipartContents(t, req, false)
    225 	if err := req.ParseMultipartForm(25); err != nil {
    226 		t.Fatal("ParseMultipartForm second call:", err)
    227 	}
    228 	validateTestMultipartContents(t, req, false)
    229 }
    230 
    231 func TestMultipartRequestAuto(t *testing.T) {
    232 	// Test that FormValue and FormFile automatically invoke
    233 	// ParseMultipartForm and return the right values.
    234 	req := newTestMultipartRequest(t)
    235 	defer func() {
    236 		if req.MultipartForm != nil {
    237 			req.MultipartForm.RemoveAll()
    238 		}
    239 	}()
    240 	validateTestMultipartContents(t, req, true)
    241 }
    242 
    243 func TestMissingFileMultipartRequest(t *testing.T) {
    244 	// Test that FormFile returns an error if
    245 	// the named file is missing.
    246 	req := newTestMultipartRequest(t)
    247 	testMissingFile(t, req)
    248 }
    249 
    250 // Test that FormValue invokes ParseMultipartForm.
    251 func TestFormValueCallsParseMultipartForm(t *testing.T) {
    252 	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
    253 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    254 	if req.Form != nil {
    255 		t.Fatal("Unexpected request Form, want nil")
    256 	}
    257 	req.FormValue("z")
    258 	if req.Form == nil {
    259 		t.Fatal("ParseMultipartForm not called by FormValue")
    260 	}
    261 }
    262 
    263 // Test that FormFile invokes ParseMultipartForm.
    264 func TestFormFileCallsParseMultipartForm(t *testing.T) {
    265 	req := newTestMultipartRequest(t)
    266 	if req.Form != nil {
    267 		t.Fatal("Unexpected request Form, want nil")
    268 	}
    269 	req.FormFile("")
    270 	if req.Form == nil {
    271 		t.Fatal("ParseMultipartForm not called by FormFile")
    272 	}
    273 }
    274 
    275 // Test that ParseMultipartForm errors if called
    276 // after MultipartReader on the same request.
    277 func TestParseMultipartFormOrder(t *testing.T) {
    278 	req := newTestMultipartRequest(t)
    279 	if _, err := req.MultipartReader(); err != nil {
    280 		t.Fatalf("MultipartReader: %v", err)
    281 	}
    282 	if err := req.ParseMultipartForm(1024); err == nil {
    283 		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
    284 	}
    285 }
    286 
    287 // Test that MultipartReader errors if called
    288 // after ParseMultipartForm on the same request.
    289 func TestMultipartReaderOrder(t *testing.T) {
    290 	req := newTestMultipartRequest(t)
    291 	if err := req.ParseMultipartForm(25); err != nil {
    292 		t.Fatalf("ParseMultipartForm: %v", err)
    293 	}
    294 	defer req.MultipartForm.RemoveAll()
    295 	if _, err := req.MultipartReader(); err == nil {
    296 		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
    297 	}
    298 }
    299 
    300 // Test that FormFile errors if called after
    301 // MultipartReader on the same request.
    302 func TestFormFileOrder(t *testing.T) {
    303 	req := newTestMultipartRequest(t)
    304 	if _, err := req.MultipartReader(); err != nil {
    305 		t.Fatalf("MultipartReader: %v", err)
    306 	}
    307 	if _, _, err := req.FormFile(""); err == nil {
    308 		t.Fatal("expected an error from FormFile after call to MultipartReader")
    309 	}
    310 }
    311 
    312 var readRequestErrorTests = []struct {
    313 	in  string
    314 	err error
    315 }{
    316 	{"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
    317 	{"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
    318 	{"", io.EOF},
    319 }
    320 
    321 func TestReadRequestErrors(t *testing.T) {
    322 	for i, tt := range readRequestErrorTests {
    323 		_, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
    324 		if err != tt.err {
    325 			t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
    326 		}
    327 	}
    328 }
    329 
    330 var newRequestHostTests = []struct {
    331 	in, out string
    332 }{
    333 	{"http://www.example.com/", "www.example.com"},
    334 	{"http://www.example.com:8080/", "www.example.com:8080"},
    335 
    336 	{"http://192.168.0.1/", "192.168.0.1"},
    337 	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
    338 
    339 	{"http://[fe80::1]/", "[fe80::1]"},
    340 	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
    341 	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
    342 	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
    343 }
    344 
    345 func TestNewRequestHost(t *testing.T) {
    346 	for i, tt := range newRequestHostTests {
    347 		req, err := NewRequest("GET", tt.in, nil)
    348 		if err != nil {
    349 			t.Errorf("#%v: %v", i, err)
    350 			continue
    351 		}
    352 		if req.Host != tt.out {
    353 			t.Errorf("got %q; want %q", req.Host, tt.out)
    354 		}
    355 	}
    356 }
    357 
    358 func TestNewRequestContentLength(t *testing.T) {
    359 	readByte := func(r io.Reader) io.Reader {
    360 		var b [1]byte
    361 		r.Read(b[:])
    362 		return r
    363 	}
    364 	tests := []struct {
    365 		r    io.Reader
    366 		want int64
    367 	}{
    368 		{bytes.NewReader([]byte("123")), 3},
    369 		{bytes.NewBuffer([]byte("1234")), 4},
    370 		{strings.NewReader("12345"), 5},
    371 		// Not detected:
    372 		{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
    373 		{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
    374 		{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
    375 	}
    376 	for _, tt := range tests {
    377 		req, err := NewRequest("POST", "http://localhost/", tt.r)
    378 		if err != nil {
    379 			t.Fatal(err)
    380 		}
    381 		if req.ContentLength != tt.want {
    382 			t.Errorf("ContentLength(%T) = %d; want %d", tt.r, req.ContentLength, tt.want)
    383 		}
    384 	}
    385 }
    386 
    387 var parseHTTPVersionTests = []struct {
    388 	vers         string
    389 	major, minor int
    390 	ok           bool
    391 }{
    392 	{"HTTP/0.9", 0, 9, true},
    393 	{"HTTP/1.0", 1, 0, true},
    394 	{"HTTP/1.1", 1, 1, true},
    395 	{"HTTP/3.14", 3, 14, true},
    396 
    397 	{"HTTP", 0, 0, false},
    398 	{"HTTP/one.one", 0, 0, false},
    399 	{"HTTP/1.1/", 0, 0, false},
    400 	{"HTTP/-1,0", 0, 0, false},
    401 	{"HTTP/0,-1", 0, 0, false},
    402 	{"HTTP/", 0, 0, false},
    403 	{"HTTP/1,1", 0, 0, false},
    404 }
    405 
    406 func TestParseHTTPVersion(t *testing.T) {
    407 	for _, tt := range parseHTTPVersionTests {
    408 		major, minor, ok := ParseHTTPVersion(tt.vers)
    409 		if ok != tt.ok || major != tt.major || minor != tt.minor {
    410 			type version struct {
    411 				major, minor int
    412 				ok           bool
    413 			}
    414 			t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
    415 		}
    416 	}
    417 }
    418 
    419 type getBasicAuthTest struct {
    420 	username, password string
    421 	ok                 bool
    422 }
    423 
    424 type basicAuthCredentialsTest struct {
    425 	username, password string
    426 }
    427 
    428 var getBasicAuthTests = []struct {
    429 	username, password string
    430 	ok                 bool
    431 }{
    432 	{"Aladdin", "open sesame", true},
    433 	{"Aladdin", "open:sesame", true},
    434 	{"", "", true},
    435 }
    436 
    437 func TestGetBasicAuth(t *testing.T) {
    438 	for _, tt := range getBasicAuthTests {
    439 		r, _ := NewRequest("GET", "http://example.com/", nil)
    440 		r.SetBasicAuth(tt.username, tt.password)
    441 		username, password, ok := r.BasicAuth()
    442 		if ok != tt.ok || username != tt.username || password != tt.password {
    443 			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
    444 				getBasicAuthTest{tt.username, tt.password, tt.ok})
    445 		}
    446 	}
    447 	// Unauthenticated request.
    448 	r, _ := NewRequest("GET", "http://example.com/", nil)
    449 	username, password, ok := r.BasicAuth()
    450 	if ok {
    451 		t.Errorf("expected false from BasicAuth when the request is unauthenticated")
    452 	}
    453 	want := basicAuthCredentialsTest{"", ""}
    454 	if username != want.username || password != want.password {
    455 		t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v",
    456 			want, basicAuthCredentialsTest{username, password})
    457 	}
    458 }
    459 
    460 var parseBasicAuthTests = []struct {
    461 	header, username, password string
    462 	ok                         bool
    463 }{
    464 	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
    465 	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true},
    466 	{"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true},
    467 	{"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
    468 	{base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
    469 	{"Basic ", "", "", false},
    470 	{"Basic Aladdin:open sesame", "", "", false},
    471 	{`Digest username="Aladdin"`, "", "", false},
    472 }
    473 
    474 func TestParseBasicAuth(t *testing.T) {
    475 	for _, tt := range parseBasicAuthTests {
    476 		r, _ := NewRequest("GET", "http://example.com/", nil)
    477 		r.Header.Set("Authorization", tt.header)
    478 		username, password, ok := r.BasicAuth()
    479 		if ok != tt.ok || username != tt.username || password != tt.password {
    480 			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
    481 				getBasicAuthTest{tt.username, tt.password, tt.ok})
    482 		}
    483 	}
    484 }
    485 
    486 type logWrites struct {
    487 	t   *testing.T
    488 	dst *[]string
    489 }
    490 
    491 func (l logWrites) WriteByte(c byte) error {
    492 	l.t.Fatalf("unexpected WriteByte call")
    493 	return nil
    494 }
    495 
    496 func (l logWrites) Write(p []byte) (n int, err error) {
    497 	*l.dst = append(*l.dst, string(p))
    498 	return len(p), nil
    499 }
    500 
    501 func TestRequestWriteBufferedWriter(t *testing.T) {
    502 	got := []string{}
    503 	req, _ := NewRequest("GET", "http://foo.com/", nil)
    504 	req.Write(logWrites{t, &got})
    505 	want := []string{
    506 		"GET / HTTP/1.1\r\n",
    507 		"Host: foo.com\r\n",
    508 		"User-Agent: " + DefaultUserAgent + "\r\n",
    509 		"\r\n",
    510 	}
    511 	if !reflect.DeepEqual(got, want) {
    512 		t.Errorf("Writes = %q\n  Want = %q", got, want)
    513 	}
    514 }
    515 
    516 func TestRequestBadHost(t *testing.T) {
    517 	got := []string{}
    518 	req, err := NewRequest("GET", "http://foo.com with spaces/after", nil)
    519 	if err != nil {
    520 		t.Fatal(err)
    521 	}
    522 	req.Write(logWrites{t, &got})
    523 	want := []string{
    524 		"GET /after HTTP/1.1\r\n",
    525 		"Host: foo.com\r\n",
    526 		"User-Agent: " + DefaultUserAgent + "\r\n",
    527 		"\r\n",
    528 	}
    529 	if !reflect.DeepEqual(got, want) {
    530 		t.Errorf("Writes = %q\n  Want = %q", got, want)
    531 	}
    532 }
    533 
    534 func TestStarRequest(t *testing.T) {
    535 	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
    536 	if err != nil {
    537 		return
    538 	}
    539 	var out bytes.Buffer
    540 	if err := req.Write(&out); err != nil {
    541 		t.Fatal(err)
    542 	}
    543 	back, err := ReadRequest(bufio.NewReader(&out))
    544 	if err != nil {
    545 		t.Fatal(err)
    546 	}
    547 	// Ignore the Headers (the User-Agent breaks the deep equal,
    548 	// but we don't care about it)
    549 	req.Header = nil
    550 	back.Header = nil
    551 	if !reflect.DeepEqual(req, back) {
    552 		t.Errorf("Original request doesn't match Request read back.")
    553 		t.Logf("Original: %#v", req)
    554 		t.Logf("Original.URL: %#v", req.URL)
    555 		t.Logf("Wrote: %s", out.Bytes())
    556 		t.Logf("Read back (doesn't match Original): %#v", back)
    557 	}
    558 }
    559 
    560 type responseWriterJustWriter struct {
    561 	io.Writer
    562 }
    563 
    564 func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
    565 func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
    566 
    567 // delayedEOFReader never returns (n > 0, io.EOF), instead putting
    568 // off the io.EOF until a subsequent Read call.
    569 type delayedEOFReader struct {
    570 	r io.Reader
    571 }
    572 
    573 func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
    574 	n, err = dr.r.Read(p)
    575 	if n > 0 && err == io.EOF {
    576 		err = nil
    577 	}
    578 	return
    579 }
    580 
    581 func TestIssue10884_MaxBytesEOF(t *testing.T) {
    582 	dst := ioutil.Discard
    583 	_, err := io.Copy(dst, MaxBytesReader(
    584 		responseWriterJustWriter{dst},
    585 		ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
    586 		5))
    587 	if err != nil {
    588 		t.Fatal(err)
    589 	}
    590 }
    591 
    592 func testMissingFile(t *testing.T, req *Request) {
    593 	f, fh, err := req.FormFile("missing")
    594 	if f != nil {
    595 		t.Errorf("FormFile file = %v, want nil", f)
    596 	}
    597 	if fh != nil {
    598 		t.Errorf("FormFile file header = %q, want nil", fh)
    599 	}
    600 	if err != ErrMissingFile {
    601 		t.Errorf("FormFile err = %q, want ErrMissingFile", err)
    602 	}
    603 }
    604 
    605 func newTestMultipartRequest(t *testing.T) *Request {
    606 	b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
    607 	req, err := NewRequest("POST", "/", b)
    608 	if err != nil {
    609 		t.Fatal("NewRequest:", err)
    610 	}
    611 	ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
    612 	req.Header.Set("Content-type", ctype)
    613 	return req
    614 }
    615 
    616 func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
    617 	if g, e := req.FormValue("texta"), textaValue; g != e {
    618 		t.Errorf("texta value = %q, want %q", g, e)
    619 	}
    620 	if g, e := req.FormValue("textb"), textbValue; g != e {
    621 		t.Errorf("textb value = %q, want %q", g, e)
    622 	}
    623 	if g := req.FormValue("missing"); g != "" {
    624 		t.Errorf("missing value = %q, want empty string", g)
    625 	}
    626 
    627 	assertMem := func(n string, fd multipart.File) {
    628 		if _, ok := fd.(*os.File); ok {
    629 			t.Error(n, " is *os.File, should not be")
    630 		}
    631 	}
    632 	fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
    633 	defer fda.Close()
    634 	assertMem("filea", fda)
    635 	fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
    636 	defer fdb.Close()
    637 	if allMem {
    638 		assertMem("fileb", fdb)
    639 	} else {
    640 		if _, ok := fdb.(*os.File); !ok {
    641 			t.Errorf("fileb has unexpected underlying type %T", fdb)
    642 		}
    643 	}
    644 
    645 	testMissingFile(t, req)
    646 }
    647 
    648 func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
    649 	f, fh, err := req.FormFile(key)
    650 	if err != nil {
    651 		t.Fatalf("FormFile(%q): %q", key, err)
    652 	}
    653 	if fh.Filename != expectFilename {
    654 		t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
    655 	}
    656 	var b bytes.Buffer
    657 	_, err = io.Copy(&b, f)
    658 	if err != nil {
    659 		t.Fatal("copying contents:", err)
    660 	}
    661 	if g := b.String(); g != expectContent {
    662 		t.Errorf("contents = %q, want %q", g, expectContent)
    663 	}
    664 	return f
    665 }
    666 
    667 const (
    668 	fileaContents = "This is a test file."
    669 	filebContents = "Another test file."
    670 	textaValue    = "foo"
    671 	textbValue    = "bar"
    672 	boundary      = `MyBoundary`
    673 )
    674 
    675 const message = `
    676 --MyBoundary
    677 Content-Disposition: form-data; name="filea"; filename="filea.txt"
    678 Content-Type: text/plain
    679 
    680 ` + fileaContents + `
    681 --MyBoundary
    682 Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
    683 Content-Type: text/plain
    684 
    685 ` + filebContents + `
    686 --MyBoundary
    687 Content-Disposition: form-data; name="texta"
    688 
    689 ` + textaValue + `
    690 --MyBoundary
    691 Content-Disposition: form-data; name="textb"
    692 
    693 ` + textbValue + `
    694 --MyBoundary--
    695 `
    696 
    697 func benchmarkReadRequest(b *testing.B, request string) {
    698 	request = request + "\n"                             // final \n
    699 	request = strings.Replace(request, "\n", "\r\n", -1) // expand \n to \r\n
    700 	b.SetBytes(int64(len(request)))
    701 	r := bufio.NewReader(&infiniteReader{buf: []byte(request)})
    702 	b.ReportAllocs()
    703 	b.ResetTimer()
    704 	for i := 0; i < b.N; i++ {
    705 		_, err := ReadRequest(r)
    706 		if err != nil {
    707 			b.Fatalf("failed to read request: %v", err)
    708 		}
    709 	}
    710 }
    711 
    712 // infiniteReader satisfies Read requests as if the contents of buf
    713 // loop indefinitely.
    714 type infiniteReader struct {
    715 	buf    []byte
    716 	offset int
    717 }
    718 
    719 func (r *infiniteReader) Read(b []byte) (int, error) {
    720 	n := copy(b, r.buf[r.offset:])
    721 	r.offset = (r.offset + n) % len(r.buf)
    722 	return n, nil
    723 }
    724 
    725 func BenchmarkReadRequestChrome(b *testing.B) {
    726 	// https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http
    727 	benchmarkReadRequest(b, `GET / HTTP/1.1
    728 Host: localhost:8080
    729 Connection: keep-alive
    730 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    731 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
    732 Accept-Encoding: gzip,deflate,sdch
    733 Accept-Language: en-US,en;q=0.8
    734 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
    735 Cookie: __utma=1.1978842379.1323102373.1323102373.1323102373.1; EPi:NumberOfVisits=1,2012-02-28T13:42:18; CrmSession=5b707226b9563e1bc69084d07a107c98; plushContainerWidth=100%25; plushNoTopMenu=0; hudson_auto_refresh=false
    736 `)
    737 }
    738 
    739 func BenchmarkReadRequestCurl(b *testing.B) {
    740 	// curl http://localhost:8080/
    741 	benchmarkReadRequest(b, `GET / HTTP/1.1
    742 User-Agent: curl/7.27.0
    743 Host: localhost:8080
    744 Accept: */*
    745 `)
    746 }
    747 
    748 func BenchmarkReadRequestApachebench(b *testing.B) {
    749 	// ab -n 1 -c 1 http://localhost:8080/
    750 	benchmarkReadRequest(b, `GET / HTTP/1.0
    751 Host: localhost:8080
    752 User-Agent: ApacheBench/2.3
    753 Accept: */*
    754 `)
    755 }
    756 
    757 func BenchmarkReadRequestSiege(b *testing.B) {
    758 	// siege -r 1 -c 1 http://localhost:8080/
    759 	benchmarkReadRequest(b, `GET / HTTP/1.1
    760 Host: localhost:8080
    761 Accept: */*
    762 Accept-Encoding: gzip
    763 User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70)
    764 Connection: keep-alive
    765 `)
    766 }
    767 
    768 func BenchmarkReadRequestWrk(b *testing.B) {
    769 	// wrk -t 1 -r 1 -c 1 http://localhost:8080/
    770 	benchmarkReadRequest(b, `GET / HTTP/1.1
    771 Host: localhost:8080
    772 `)
    773 }
    774