PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/third_party/gofrontend/libgo/go/net/http/request_test.go

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