github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/net/http/request_test.go (about)

     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  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"mime/multipart"
    14  	. "net/http"
    15  	"net/http/httptest"
    16  	"net/url"
    17  	"os"
    18  	"reflect"
    19  	"regexp"
    20  	"strings"
    21  	"testing"
    22  )
    23  
    24  func TestQuery(t *testing.T) {
    25  	req := &Request{Method: "GET"}
    26  	req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
    27  	if q := req.FormValue("q"); q != "foo" {
    28  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    29  	}
    30  }
    31  
    32  func TestPostQuery(t *testing.T) {
    33  	req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
    34  		strings.NewReader("z=post&both=y&prio=2&empty="))
    35  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    36  
    37  	if q := req.FormValue("q"); q != "foo" {
    38  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    39  	}
    40  	if z := req.FormValue("z"); z != "post" {
    41  		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
    42  	}
    43  	if bq, found := req.PostForm["q"]; found {
    44  		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
    45  	}
    46  	if bz := req.PostFormValue("z"); bz != "post" {
    47  		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
    48  	}
    49  	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
    50  		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
    51  	}
    52  	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
    53  		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
    54  	}
    55  	if prio := req.FormValue("prio"); prio != "2" {
    56  		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
    57  	}
    58  	if empty := req.FormValue("empty"); empty != "" {
    59  		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
    60  	}
    61  }
    62  
    63  func TestPatchQuery(t *testing.T) {
    64  	req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
    65  		strings.NewReader("z=post&both=y&prio=2&empty="))
    66  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    67  
    68  	if q := req.FormValue("q"); q != "foo" {
    69  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    70  	}
    71  	if z := req.FormValue("z"); z != "post" {
    72  		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
    73  	}
    74  	if bq, found := req.PostForm["q"]; found {
    75  		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
    76  	}
    77  	if bz := req.PostFormValue("z"); bz != "post" {
    78  		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
    79  	}
    80  	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
    81  		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
    82  	}
    83  	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
    84  		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
    85  	}
    86  	if prio := req.FormValue("prio"); prio != "2" {
    87  		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
    88  	}
    89  	if empty := req.FormValue("empty"); empty != "" {
    90  		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
    91  	}
    92  }
    93  
    94  type stringMap map[string][]string
    95  type parseContentTypeTest struct {
    96  	shouldError bool
    97  	contentType stringMap
    98  }
    99  
   100  var parseContentTypeTests = []parseContentTypeTest{
   101  	{false, stringMap{"Content-Type": {"text/plain"}}},
   102  	// Empty content type is legal - shoult be treated as
   103  	// application/octet-stream (RFC 2616, section 7.2.1)
   104  	{false, stringMap{}},
   105  	{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
   106  	{false, stringMap{"Content-Type": {"application/unknown"}}},
   107  }
   108  
   109  func TestParseFormUnknownContentType(t *testing.T) {
   110  	for i, test := range parseContentTypeTests {
   111  		req := &Request{
   112  			Method: "POST",
   113  			Header: Header(test.contentType),
   114  			Body:   ioutil.NopCloser(strings.NewReader("body")),
   115  		}
   116  		err := req.ParseForm()
   117  		switch {
   118  		case err == nil && test.shouldError:
   119  			t.Errorf("test %d should have returned error", i)
   120  		case err != nil && !test.shouldError:
   121  			t.Errorf("test %d should not have returned error, got %v", i, err)
   122  		}
   123  	}
   124  }
   125  
   126  func TestParseFormInitializeOnError(t *testing.T) {
   127  	nilBody, _ := NewRequest("POST", "http://www.google.com/search?q=foo", nil)
   128  	tests := []*Request{
   129  		nilBody,
   130  		{Method: "GET", URL: nil},
   131  	}
   132  	for i, req := range tests {
   133  		err := req.ParseForm()
   134  		if req.Form == nil {
   135  			t.Errorf("%d. Form not initialized, error %v", i, err)
   136  		}
   137  		if req.PostForm == nil {
   138  			t.Errorf("%d. PostForm not initialized, error %v", i, err)
   139  		}
   140  	}
   141  }
   142  
   143  func TestMultipartReader(t *testing.T) {
   144  	req := &Request{
   145  		Method: "POST",
   146  		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
   147  		Body:   ioutil.NopCloser(new(bytes.Buffer)),
   148  	}
   149  	multipart, err := req.MultipartReader()
   150  	if multipart == nil {
   151  		t.Errorf("expected multipart; error: %v", err)
   152  	}
   153  
   154  	req.Header = Header{"Content-Type": {"text/plain"}}
   155  	multipart, err = req.MultipartReader()
   156  	if multipart != nil {
   157  		t.Error("unexpected multipart for text/plain")
   158  	}
   159  }
   160  
   161  func TestParseMultipartForm(t *testing.T) {
   162  	req := &Request{
   163  		Method: "POST",
   164  		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
   165  		Body:   ioutil.NopCloser(new(bytes.Buffer)),
   166  	}
   167  	err := req.ParseMultipartForm(25)
   168  	if err == nil {
   169  		t.Error("expected multipart EOF, got nil")
   170  	}
   171  
   172  	req.Header = Header{"Content-Type": {"text/plain"}}
   173  	err = req.ParseMultipartForm(25)
   174  	if err != ErrNotMultipart {
   175  		t.Error("expected ErrNotMultipart for text/plain")
   176  	}
   177  }
   178  
   179  func TestRedirect(t *testing.T) {
   180  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   181  		switch r.URL.Path {
   182  		case "/":
   183  			w.Header().Set("Location", "/foo/")
   184  			w.WriteHeader(StatusSeeOther)
   185  		case "/foo/":
   186  			fmt.Fprintf(w, "foo")
   187  		default:
   188  			w.WriteHeader(StatusBadRequest)
   189  		}
   190  	}))
   191  	defer ts.Close()
   192  
   193  	var end = regexp.MustCompile("/foo/$")
   194  	r, err := Get(ts.URL)
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  	r.Body.Close()
   199  	url := r.Request.URL.String()
   200  	if r.StatusCode != 200 || !end.MatchString(url) {
   201  		t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
   202  	}
   203  }
   204  
   205  func TestSetBasicAuth(t *testing.T) {
   206  	r, _ := NewRequest("GET", "http://example.com/", nil)
   207  	r.SetBasicAuth("Aladdin", "open sesame")
   208  	if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
   209  		t.Errorf("got header %q, want %q", g, e)
   210  	}
   211  }
   212  
   213  func TestMultipartRequest(t *testing.T) {
   214  	// Test that we can read the values and files of a
   215  	// multipart request with FormValue and FormFile,
   216  	// and that ParseMultipartForm can be called multiple times.
   217  	req := newTestMultipartRequest(t)
   218  	if err := req.ParseMultipartForm(25); err != nil {
   219  		t.Fatal("ParseMultipartForm first call:", err)
   220  	}
   221  	defer req.MultipartForm.RemoveAll()
   222  	validateTestMultipartContents(t, req, false)
   223  	if err := req.ParseMultipartForm(25); err != nil {
   224  		t.Fatal("ParseMultipartForm second call:", err)
   225  	}
   226  	validateTestMultipartContents(t, req, false)
   227  }
   228  
   229  func TestMultipartRequestAuto(t *testing.T) {
   230  	// Test that FormValue and FormFile automatically invoke
   231  	// ParseMultipartForm and return the right values.
   232  	req := newTestMultipartRequest(t)
   233  	defer func() {
   234  		if req.MultipartForm != nil {
   235  			req.MultipartForm.RemoveAll()
   236  		}
   237  	}()
   238  	validateTestMultipartContents(t, req, true)
   239  }
   240  
   241  func TestMissingFileMultipartRequest(t *testing.T) {
   242  	// Test that FormFile returns an error if
   243  	// the named file is missing.
   244  	req := newTestMultipartRequest(t)
   245  	testMissingFile(t, req)
   246  }
   247  
   248  // Test that FormValue invokes ParseMultipartForm.
   249  func TestFormValueCallsParseMultipartForm(t *testing.T) {
   250  	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
   251  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
   252  	if req.Form != nil {
   253  		t.Fatal("Unexpected request Form, want nil")
   254  	}
   255  	req.FormValue("z")
   256  	if req.Form == nil {
   257  		t.Fatal("ParseMultipartForm not called by FormValue")
   258  	}
   259  }
   260  
   261  // Test that FormFile invokes ParseMultipartForm.
   262  func TestFormFileCallsParseMultipartForm(t *testing.T) {
   263  	req := newTestMultipartRequest(t)
   264  	if req.Form != nil {
   265  		t.Fatal("Unexpected request Form, want nil")
   266  	}
   267  	req.FormFile("")
   268  	if req.Form == nil {
   269  		t.Fatal("ParseMultipartForm not called by FormFile")
   270  	}
   271  }
   272  
   273  // Test that ParseMultipartForm errors if called
   274  // after MultipartReader on the same request.
   275  func TestParseMultipartFormOrder(t *testing.T) {
   276  	req := newTestMultipartRequest(t)
   277  	if _, err := req.MultipartReader(); err != nil {
   278  		t.Fatalf("MultipartReader: %v", err)
   279  	}
   280  	if err := req.ParseMultipartForm(1024); err == nil {
   281  		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
   282  	}
   283  }
   284  
   285  // Test that MultipartReader errors if called
   286  // after ParseMultipartForm on the same request.
   287  func TestMultipartReaderOrder(t *testing.T) {
   288  	req := newTestMultipartRequest(t)
   289  	if err := req.ParseMultipartForm(25); err != nil {
   290  		t.Fatalf("ParseMultipartForm: %v", err)
   291  	}
   292  	defer req.MultipartForm.RemoveAll()
   293  	if _, err := req.MultipartReader(); err == nil {
   294  		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
   295  	}
   296  }
   297  
   298  // Test that FormFile errors if called after
   299  // MultipartReader on the same request.
   300  func TestFormFileOrder(t *testing.T) {
   301  	req := newTestMultipartRequest(t)
   302  	if _, err := req.MultipartReader(); err != nil {
   303  		t.Fatalf("MultipartReader: %v", err)
   304  	}
   305  	if _, _, err := req.FormFile(""); err == nil {
   306  		t.Fatal("expected an error from FormFile after call to MultipartReader")
   307  	}
   308  }
   309  
   310  var readRequestErrorTests = []struct {
   311  	in  string
   312  	err error
   313  }{
   314  	{"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
   315  	{"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
   316  	{"", io.EOF},
   317  }
   318  
   319  func TestReadRequestErrors(t *testing.T) {
   320  	for i, tt := range readRequestErrorTests {
   321  		_, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
   322  		if err != tt.err {
   323  			t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
   324  		}
   325  	}
   326  }
   327  
   328  func TestNewRequestHost(t *testing.T) {
   329  	req, err := NewRequest("GET", "http://localhost:1234/", nil)
   330  	if err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	if req.Host != "localhost:1234" {
   334  		t.Errorf("Host = %q; want localhost:1234", req.Host)
   335  	}
   336  }
   337  
   338  func TestNewRequestContentLength(t *testing.T) {
   339  	readByte := func(r io.Reader) io.Reader {
   340  		var b [1]byte
   341  		r.Read(b[:])
   342  		return r
   343  	}
   344  	tests := []struct {
   345  		r    io.Reader
   346  		want int64
   347  	}{
   348  		{bytes.NewReader([]byte("123")), 3},
   349  		{bytes.NewBuffer([]byte("1234")), 4},
   350  		{strings.NewReader("12345"), 5},
   351  		// Not detected:
   352  		{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
   353  		{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
   354  		{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
   355  	}
   356  	for _, tt := range tests {
   357  		req, err := NewRequest("POST", "http://localhost/", tt.r)
   358  		if err != nil {
   359  			t.Fatal(err)
   360  		}
   361  		if req.ContentLength != tt.want {
   362  			t.Errorf("ContentLength(%T) = %d; want %d", tt.r, req.ContentLength, tt.want)
   363  		}
   364  	}
   365  }
   366  
   367  var parseHTTPVersionTests = []struct {
   368  	vers         string
   369  	major, minor int
   370  	ok           bool
   371  }{
   372  	{"HTTP/0.9", 0, 9, true},
   373  	{"HTTP/1.0", 1, 0, true},
   374  	{"HTTP/1.1", 1, 1, true},
   375  	{"HTTP/3.14", 3, 14, true},
   376  
   377  	{"HTTP", 0, 0, false},
   378  	{"HTTP/one.one", 0, 0, false},
   379  	{"HTTP/1.1/", 0, 0, false},
   380  	{"HTTP/-1,0", 0, 0, false},
   381  	{"HTTP/0,-1", 0, 0, false},
   382  	{"HTTP/", 0, 0, false},
   383  	{"HTTP/1,1", 0, 0, false},
   384  }
   385  
   386  func TestParseHTTPVersion(t *testing.T) {
   387  	for _, tt := range parseHTTPVersionTests {
   388  		major, minor, ok := ParseHTTPVersion(tt.vers)
   389  		if ok != tt.ok || major != tt.major || minor != tt.minor {
   390  			type version struct {
   391  				major, minor int
   392  				ok           bool
   393  			}
   394  			t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
   395  		}
   396  	}
   397  }
   398  
   399  type logWrites struct {
   400  	t   *testing.T
   401  	dst *[]string
   402  }
   403  
   404  func (l logWrites) WriteByte(c byte) error {
   405  	l.t.Fatalf("unexpected WriteByte call")
   406  	return nil
   407  }
   408  
   409  func (l logWrites) Write(p []byte) (n int, err error) {
   410  	*l.dst = append(*l.dst, string(p))
   411  	return len(p), nil
   412  }
   413  
   414  func TestRequestWriteBufferedWriter(t *testing.T) {
   415  	got := []string{}
   416  	req, _ := NewRequest("GET", "http://foo.com/", nil)
   417  	req.Write(logWrites{t, &got})
   418  	want := []string{
   419  		"GET / HTTP/1.1\r\n",
   420  		"Host: foo.com\r\n",
   421  		"User-Agent: " + DefaultUserAgent + "\r\n",
   422  		"\r\n",
   423  	}
   424  	if !reflect.DeepEqual(got, want) {
   425  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   426  	}
   427  }
   428  
   429  func testMissingFile(t *testing.T, req *Request) {
   430  	f, fh, err := req.FormFile("missing")
   431  	if f != nil {
   432  		t.Errorf("FormFile file = %v, want nil", f)
   433  	}
   434  	if fh != nil {
   435  		t.Errorf("FormFile file header = %q, want nil", fh)
   436  	}
   437  	if err != ErrMissingFile {
   438  		t.Errorf("FormFile err = %q, want ErrMissingFile", err)
   439  	}
   440  }
   441  
   442  func newTestMultipartRequest(t *testing.T) *Request {
   443  	b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
   444  	req, err := NewRequest("POST", "/", b)
   445  	if err != nil {
   446  		t.Fatal("NewRequest:", err)
   447  	}
   448  	ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
   449  	req.Header.Set("Content-type", ctype)
   450  	return req
   451  }
   452  
   453  func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
   454  	if g, e := req.FormValue("texta"), textaValue; g != e {
   455  		t.Errorf("texta value = %q, want %q", g, e)
   456  	}
   457  	if g, e := req.FormValue("textb"), textbValue; g != e {
   458  		t.Errorf("textb value = %q, want %q", g, e)
   459  	}
   460  	if g := req.FormValue("missing"); g != "" {
   461  		t.Errorf("missing value = %q, want empty string", g)
   462  	}
   463  
   464  	assertMem := func(n string, fd multipart.File) {
   465  		if _, ok := fd.(*os.File); ok {
   466  			t.Error(n, " is *os.File, should not be")
   467  		}
   468  	}
   469  	fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
   470  	defer fda.Close()
   471  	assertMem("filea", fda)
   472  	fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
   473  	defer fdb.Close()
   474  	if allMem {
   475  		assertMem("fileb", fdb)
   476  	} else {
   477  		if _, ok := fdb.(*os.File); !ok {
   478  			t.Errorf("fileb has unexpected underlying type %T", fdb)
   479  		}
   480  	}
   481  
   482  	testMissingFile(t, req)
   483  }
   484  
   485  func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
   486  	f, fh, err := req.FormFile(key)
   487  	if err != nil {
   488  		t.Fatalf("FormFile(%q): %q", key, err)
   489  	}
   490  	if fh.Filename != expectFilename {
   491  		t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
   492  	}
   493  	var b bytes.Buffer
   494  	_, err = io.Copy(&b, f)
   495  	if err != nil {
   496  		t.Fatal("copying contents:", err)
   497  	}
   498  	if g := b.String(); g != expectContent {
   499  		t.Errorf("contents = %q, want %q", g, expectContent)
   500  	}
   501  	return f
   502  }
   503  
   504  const (
   505  	fileaContents = "This is a test file."
   506  	filebContents = "Another test file."
   507  	textaValue    = "foo"
   508  	textbValue    = "bar"
   509  	boundary      = `MyBoundary`
   510  )
   511  
   512  const message = `
   513  --MyBoundary
   514  Content-Disposition: form-data; name="filea"; filename="filea.txt"
   515  Content-Type: text/plain
   516  
   517  ` + fileaContents + `
   518  --MyBoundary
   519  Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
   520  Content-Type: text/plain
   521  
   522  ` + filebContents + `
   523  --MyBoundary
   524  Content-Disposition: form-data; name="texta"
   525  
   526  ` + textaValue + `
   527  --MyBoundary
   528  Content-Disposition: form-data; name="textb"
   529  
   530  ` + textbValue + `
   531  --MyBoundary--
   532  `
   533  
   534  func benchmarkReadRequest(b *testing.B, request string) {
   535  	request = request + "\n"                             // final \n
   536  	request = strings.Replace(request, "\n", "\r\n", -1) // expand \n to \r\n
   537  	b.SetBytes(int64(len(request)))
   538  	r := bufio.NewReader(&infiniteReader{buf: []byte(request)})
   539  	b.ReportAllocs()
   540  	b.ResetTimer()
   541  	for i := 0; i < b.N; i++ {
   542  		_, err := ReadRequest(r)
   543  		if err != nil {
   544  			b.Fatalf("failed to read request: %v", err)
   545  		}
   546  	}
   547  }
   548  
   549  // infiniteReader satisfies Read requests as if the contents of buf
   550  // loop indefinitely.
   551  type infiniteReader struct {
   552  	buf    []byte
   553  	offset int
   554  }
   555  
   556  func (r *infiniteReader) Read(b []byte) (int, error) {
   557  	n := copy(b, r.buf[r.offset:])
   558  	r.offset = (r.offset + n) % len(r.buf)
   559  	return n, nil
   560  }
   561  
   562  func BenchmarkReadRequestChrome(b *testing.B) {
   563  	// https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http
   564  	benchmarkReadRequest(b, `GET / HTTP/1.1
   565  Host: localhost:8080
   566  Connection: keep-alive
   567  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
   568  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
   569  Accept-Encoding: gzip,deflate,sdch
   570  Accept-Language: en-US,en;q=0.8
   571  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
   572  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
   573  `)
   574  }
   575  
   576  func BenchmarkReadRequestCurl(b *testing.B) {
   577  	// curl http://localhost:8080/
   578  	benchmarkReadRequest(b, `GET / HTTP/1.1
   579  User-Agent: curl/7.27.0
   580  Host: localhost:8080
   581  Accept: */*
   582  `)
   583  }
   584  
   585  func BenchmarkReadRequestApachebench(b *testing.B) {
   586  	// ab -n 1 -c 1 http://localhost:8080/
   587  	benchmarkReadRequest(b, `GET / HTTP/1.0
   588  Host: localhost:8080
   589  User-Agent: ApacheBench/2.3
   590  Accept: */*
   591  `)
   592  }
   593  
   594  func BenchmarkReadRequestSiege(b *testing.B) {
   595  	// siege -r 1 -c 1 http://localhost:8080/
   596  	benchmarkReadRequest(b, `GET / HTTP/1.1
   597  Host: localhost:8080
   598  Accept: */*
   599  Accept-Encoding: gzip
   600  User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70)
   601  Connection: keep-alive
   602  `)
   603  }
   604  
   605  func BenchmarkReadRequestWrk(b *testing.B) {
   606  	// wrk -t 1 -r 1 -c 1 http://localhost:8080/
   607  	benchmarkReadRequest(b, `GET / HTTP/1.1
   608  Host: localhost:8080
   609  `)
   610  }