libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / http / clientserver_test.go
blob6513b2d32fcae62418c7ab125f494cec30dd9c97
1 // Copyright 2015 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.
5 // Tests that use both the client & server, in both HTTP/1 and HTTP/2 mode.
7 package http_test
9 import (
10 "bytes"
11 "compress/gzip"
12 "crypto/tls"
13 "fmt"
14 "io"
15 "io/ioutil"
16 "log"
17 "net"
18 . "net/http"
19 "net/http/httptest"
20 "net/http/httputil"
21 "net/url"
22 "os"
23 "reflect"
24 "runtime"
25 "sort"
26 "strings"
27 "sync"
28 "sync/atomic"
29 "testing"
30 "time"
33 type clientServerTest struct {
34 t *testing.T
35 h2 bool
36 h Handler
37 ts *httptest.Server
38 tr *Transport
39 c *Client
42 func (t *clientServerTest) close() {
43 t.tr.CloseIdleConnections()
44 t.ts.Close()
47 func (t *clientServerTest) getURL(u string) string {
48 res, err := t.c.Get(u)
49 if err != nil {
50 t.t.Fatal(err)
52 defer res.Body.Close()
53 slurp, err := ioutil.ReadAll(res.Body)
54 if err != nil {
55 t.t.Fatal(err)
57 return string(slurp)
60 func (t *clientServerTest) scheme() string {
61 if t.h2 {
62 return "https"
64 return "http"
67 const (
68 h1Mode = false
69 h2Mode = true
72 var optQuietLog = func(ts *httptest.Server) {
73 ts.Config.ErrorLog = quietLog
76 func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{}) *clientServerTest {
77 cst := &clientServerTest{
78 t: t,
79 h2: h2,
80 h: h,
81 tr: &Transport{},
83 cst.c = &Client{Transport: cst.tr}
84 cst.ts = httptest.NewUnstartedServer(h)
86 for _, opt := range opts {
87 switch opt := opt.(type) {
88 case func(*Transport):
89 opt(cst.tr)
90 case func(*httptest.Server):
91 opt(cst.ts)
92 default:
93 t.Fatalf("unhandled option type %T", opt)
97 if !h2 {
98 cst.ts.Start()
99 return cst
101 ExportHttp2ConfigureServer(cst.ts.Config, nil)
102 cst.ts.TLS = cst.ts.Config.TLSConfig
103 cst.ts.StartTLS()
105 cst.tr.TLSClientConfig = &tls.Config{
106 InsecureSkipVerify: true,
108 if err := ExportHttp2ConfigureTransport(cst.tr); err != nil {
109 t.Fatal(err)
111 return cst
114 // Testing the newClientServerTest helper itself.
115 func TestNewClientServerTest(t *testing.T) {
116 var got struct {
117 sync.Mutex
118 log []string
120 h := HandlerFunc(func(w ResponseWriter, r *Request) {
121 got.Lock()
122 defer got.Unlock()
123 got.log = append(got.log, r.Proto)
125 for _, v := range [2]bool{false, true} {
126 cst := newClientServerTest(t, v, h)
127 if _, err := cst.c.Head(cst.ts.URL); err != nil {
128 t.Fatal(err)
130 cst.close()
132 got.Lock() // no need to unlock
133 if want := []string{"HTTP/1.1", "HTTP/2.0"}; !reflect.DeepEqual(got.log, want) {
134 t.Errorf("got %q; want %q", got.log, want)
138 func TestChunkedResponseHeaders_h1(t *testing.T) { testChunkedResponseHeaders(t, h1Mode) }
139 func TestChunkedResponseHeaders_h2(t *testing.T) { testChunkedResponseHeaders(t, h2Mode) }
141 func testChunkedResponseHeaders(t *testing.T, h2 bool) {
142 defer afterTest(t)
143 log.SetOutput(ioutil.Discard) // is noisy otherwise
144 defer log.SetOutput(os.Stderr)
145 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
146 w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
147 w.(Flusher).Flush()
148 fmt.Fprintf(w, "I am a chunked response.")
150 defer cst.close()
152 res, err := cst.c.Get(cst.ts.URL)
153 if err != nil {
154 t.Fatalf("Get error: %v", err)
156 defer res.Body.Close()
157 if g, e := res.ContentLength, int64(-1); g != e {
158 t.Errorf("expected ContentLength of %d; got %d", e, g)
160 wantTE := []string{"chunked"}
161 if h2 {
162 wantTE = nil
164 if !reflect.DeepEqual(res.TransferEncoding, wantTE) {
165 t.Errorf("TransferEncoding = %v; want %v", res.TransferEncoding, wantTE)
167 if got, haveCL := res.Header["Content-Length"]; haveCL {
168 t.Errorf("Unexpected Content-Length: %q", got)
172 type reqFunc func(c *Client, url string) (*Response, error)
174 // h12Compare is a test that compares HTTP/1 and HTTP/2 behavior
175 // against each other.
176 type h12Compare struct {
177 Handler func(ResponseWriter, *Request) // required
178 ReqFunc reqFunc // optional
179 CheckResponse func(proto string, res *Response) // optional
180 EarlyCheckResponse func(proto string, res *Response) // optional; pre-normalize
181 Opts []interface{}
184 func (tt h12Compare) reqFunc() reqFunc {
185 if tt.ReqFunc == nil {
186 return (*Client).Get
188 return tt.ReqFunc
191 func (tt h12Compare) run(t *testing.T) {
192 setParallel(t)
193 cst1 := newClientServerTest(t, false, HandlerFunc(tt.Handler), tt.Opts...)
194 defer cst1.close()
195 cst2 := newClientServerTest(t, true, HandlerFunc(tt.Handler), tt.Opts...)
196 defer cst2.close()
198 res1, err := tt.reqFunc()(cst1.c, cst1.ts.URL)
199 if err != nil {
200 t.Errorf("HTTP/1 request: %v", err)
201 return
203 res2, err := tt.reqFunc()(cst2.c, cst2.ts.URL)
204 if err != nil {
205 t.Errorf("HTTP/2 request: %v", err)
206 return
209 if fn := tt.EarlyCheckResponse; fn != nil {
210 fn("HTTP/1.1", res1)
211 fn("HTTP/2.0", res2)
214 tt.normalizeRes(t, res1, "HTTP/1.1")
215 tt.normalizeRes(t, res2, "HTTP/2.0")
216 res1body, res2body := res1.Body, res2.Body
218 eres1 := mostlyCopy(res1)
219 eres2 := mostlyCopy(res2)
220 if !reflect.DeepEqual(eres1, eres2) {
221 t.Errorf("Response headers to handler differed:\nhttp/1 (%v):\n\t%#v\nhttp/2 (%v):\n\t%#v",
222 cst1.ts.URL, eres1, cst2.ts.URL, eres2)
224 if !reflect.DeepEqual(res1body, res2body) {
225 t.Errorf("Response bodies to handler differed.\nhttp1: %v\nhttp2: %v\n", res1body, res2body)
227 if fn := tt.CheckResponse; fn != nil {
228 res1.Body, res2.Body = res1body, res2body
229 fn("HTTP/1.1", res1)
230 fn("HTTP/2.0", res2)
234 func mostlyCopy(r *Response) *Response {
235 c := *r
236 c.Body = nil
237 c.TransferEncoding = nil
238 c.TLS = nil
239 c.Request = nil
240 return &c
243 type slurpResult struct {
244 io.ReadCloser
245 body []byte
246 err error
249 func (sr slurpResult) String() string { return fmt.Sprintf("body %q; err %v", sr.body, sr.err) }
251 func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string) {
252 if res.Proto == wantProto {
253 res.Proto, res.ProtoMajor, res.ProtoMinor = "", 0, 0
254 } else {
255 t.Errorf("got %q response; want %q", res.Proto, wantProto)
257 slurp, err := ioutil.ReadAll(res.Body)
259 res.Body.Close()
260 res.Body = slurpResult{
261 ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)),
262 body: slurp,
263 err: err,
265 for i, v := range res.Header["Date"] {
266 res.Header["Date"][i] = strings.Repeat("x", len(v))
268 if res.Request == nil {
269 t.Errorf("for %s, no request", wantProto)
271 if (res.TLS != nil) != (wantProto == "HTTP/2.0") {
272 t.Errorf("TLS set = %v; want %v", res.TLS != nil, res.TLS == nil)
276 // Issue 13532
277 func TestH12_HeadContentLengthNoBody(t *testing.T) {
278 h12Compare{
279 ReqFunc: (*Client).Head,
280 Handler: func(w ResponseWriter, r *Request) {
282 }.run(t)
285 func TestH12_HeadContentLengthSmallBody(t *testing.T) {
286 h12Compare{
287 ReqFunc: (*Client).Head,
288 Handler: func(w ResponseWriter, r *Request) {
289 io.WriteString(w, "small")
291 }.run(t)
294 func TestH12_HeadContentLengthLargeBody(t *testing.T) {
295 h12Compare{
296 ReqFunc: (*Client).Head,
297 Handler: func(w ResponseWriter, r *Request) {
298 chunk := strings.Repeat("x", 512<<10)
299 for i := 0; i < 10; i++ {
300 io.WriteString(w, chunk)
303 }.run(t)
306 func TestH12_200NoBody(t *testing.T) {
307 h12Compare{Handler: func(w ResponseWriter, r *Request) {}}.run(t)
310 func TestH2_204NoBody(t *testing.T) { testH12_noBody(t, 204) }
311 func TestH2_304NoBody(t *testing.T) { testH12_noBody(t, 304) }
312 func TestH2_404NoBody(t *testing.T) { testH12_noBody(t, 404) }
314 func testH12_noBody(t *testing.T, status int) {
315 h12Compare{Handler: func(w ResponseWriter, r *Request) {
316 w.WriteHeader(status)
317 }}.run(t)
320 func TestH12_SmallBody(t *testing.T) {
321 h12Compare{Handler: func(w ResponseWriter, r *Request) {
322 io.WriteString(w, "small body")
323 }}.run(t)
326 func TestH12_ExplicitContentLength(t *testing.T) {
327 h12Compare{Handler: func(w ResponseWriter, r *Request) {
328 w.Header().Set("Content-Length", "3")
329 io.WriteString(w, "foo")
330 }}.run(t)
333 func TestH12_FlushBeforeBody(t *testing.T) {
334 h12Compare{Handler: func(w ResponseWriter, r *Request) {
335 w.(Flusher).Flush()
336 io.WriteString(w, "foo")
337 }}.run(t)
340 func TestH12_FlushMidBody(t *testing.T) {
341 h12Compare{Handler: func(w ResponseWriter, r *Request) {
342 io.WriteString(w, "foo")
343 w.(Flusher).Flush()
344 io.WriteString(w, "bar")
345 }}.run(t)
348 func TestH12_Head_ExplicitLen(t *testing.T) {
349 h12Compare{
350 ReqFunc: (*Client).Head,
351 Handler: func(w ResponseWriter, r *Request) {
352 if r.Method != "HEAD" {
353 t.Errorf("unexpected method %q", r.Method)
355 w.Header().Set("Content-Length", "1235")
357 }.run(t)
360 func TestH12_Head_ImplicitLen(t *testing.T) {
361 h12Compare{
362 ReqFunc: (*Client).Head,
363 Handler: func(w ResponseWriter, r *Request) {
364 if r.Method != "HEAD" {
365 t.Errorf("unexpected method %q", r.Method)
367 io.WriteString(w, "foo")
369 }.run(t)
372 func TestH12_HandlerWritesTooLittle(t *testing.T) {
373 h12Compare{
374 Handler: func(w ResponseWriter, r *Request) {
375 w.Header().Set("Content-Length", "3")
376 io.WriteString(w, "12") // one byte short
378 CheckResponse: func(proto string, res *Response) {
379 sr, ok := res.Body.(slurpResult)
380 if !ok {
381 t.Errorf("%s body is %T; want slurpResult", proto, res.Body)
382 return
384 if sr.err != io.ErrUnexpectedEOF {
385 t.Errorf("%s read error = %v; want io.ErrUnexpectedEOF", proto, sr.err)
387 if string(sr.body) != "12" {
388 t.Errorf("%s body = %q; want %q", proto, sr.body, "12")
391 }.run(t)
394 // Tests that the HTTP/1 and HTTP/2 servers prevent handlers from
395 // writing more than they declared. This test does not test whether
396 // the transport deals with too much data, though, since the server
397 // doesn't make it possible to send bogus data. For those tests, see
398 // transport_test.go (for HTTP/1) or x/net/http2/transport_test.go
399 // (for HTTP/2).
400 func TestH12_HandlerWritesTooMuch(t *testing.T) {
401 h12Compare{
402 Handler: func(w ResponseWriter, r *Request) {
403 w.Header().Set("Content-Length", "3")
404 w.(Flusher).Flush()
405 io.WriteString(w, "123")
406 w.(Flusher).Flush()
407 n, err := io.WriteString(w, "x") // too many
408 if n > 0 || err == nil {
409 t.Errorf("for proto %q, final write = %v, %v; want 0, some error", r.Proto, n, err)
412 }.run(t)
415 // Verify that both our HTTP/1 and HTTP/2 request and auto-decompress gzip.
416 // Some hosts send gzip even if you don't ask for it; see golang.org/issue/13298
417 func TestH12_AutoGzip(t *testing.T) {
418 h12Compare{
419 Handler: func(w ResponseWriter, r *Request) {
420 if ae := r.Header.Get("Accept-Encoding"); ae != "gzip" {
421 t.Errorf("%s Accept-Encoding = %q; want gzip", r.Proto, ae)
423 w.Header().Set("Content-Encoding", "gzip")
424 gz := gzip.NewWriter(w)
425 io.WriteString(gz, "I am some gzipped content. Go go go go go go go go go go go go should compress well.")
426 gz.Close()
428 }.run(t)
431 func TestH12_AutoGzip_Disabled(t *testing.T) {
432 h12Compare{
433 Opts: []interface{}{
434 func(tr *Transport) { tr.DisableCompression = true },
436 Handler: func(w ResponseWriter, r *Request) {
437 fmt.Fprintf(w, "%q", r.Header["Accept-Encoding"])
438 if ae := r.Header.Get("Accept-Encoding"); ae != "" {
439 t.Errorf("%s Accept-Encoding = %q; want empty", r.Proto, ae)
442 }.run(t)
445 // Test304Responses verifies that 304s don't declare that they're
446 // chunking in their response headers and aren't allowed to produce
447 // output.
448 func Test304Responses_h1(t *testing.T) { test304Responses(t, h1Mode) }
449 func Test304Responses_h2(t *testing.T) { test304Responses(t, h2Mode) }
451 func test304Responses(t *testing.T, h2 bool) {
452 defer afterTest(t)
453 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
454 w.WriteHeader(StatusNotModified)
455 _, err := w.Write([]byte("illegal body"))
456 if err != ErrBodyNotAllowed {
457 t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
460 defer cst.close()
461 res, err := cst.c.Get(cst.ts.URL)
462 if err != nil {
463 t.Fatal(err)
465 if len(res.TransferEncoding) > 0 {
466 t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
468 body, err := ioutil.ReadAll(res.Body)
469 if err != nil {
470 t.Error(err)
472 if len(body) > 0 {
473 t.Errorf("got unexpected body %q", string(body))
477 func TestH12_ServerEmptyContentLength(t *testing.T) {
478 h12Compare{
479 Handler: func(w ResponseWriter, r *Request) {
480 w.Header()["Content-Type"] = []string{""}
481 io.WriteString(w, "<html><body>hi</body></html>")
483 }.run(t)
486 func TestH12_RequestContentLength_Known_NonZero(t *testing.T) {
487 h12requestContentLength(t, func() io.Reader { return strings.NewReader("FOUR") }, 4)
490 func TestH12_RequestContentLength_Known_Zero(t *testing.T) {
491 h12requestContentLength(t, func() io.Reader { return nil }, 0)
494 func TestH12_RequestContentLength_Unknown(t *testing.T) {
495 h12requestContentLength(t, func() io.Reader { return struct{ io.Reader }{strings.NewReader("Stuff")} }, -1)
498 func h12requestContentLength(t *testing.T, bodyfn func() io.Reader, wantLen int64) {
499 h12Compare{
500 Handler: func(w ResponseWriter, r *Request) {
501 w.Header().Set("Got-Length", fmt.Sprint(r.ContentLength))
502 fmt.Fprintf(w, "Req.ContentLength=%v", r.ContentLength)
504 ReqFunc: func(c *Client, url string) (*Response, error) {
505 return c.Post(url, "text/plain", bodyfn())
507 CheckResponse: func(proto string, res *Response) {
508 if got, want := res.Header.Get("Got-Length"), fmt.Sprint(wantLen); got != want {
509 t.Errorf("Proto %q got length %q; want %q", proto, got, want)
512 }.run(t)
515 // Tests that closing the Request.Cancel channel also while still
516 // reading the response body. Issue 13159.
517 func TestCancelRequestMidBody_h1(t *testing.T) { testCancelRequestMidBody(t, h1Mode) }
518 func TestCancelRequestMidBody_h2(t *testing.T) { testCancelRequestMidBody(t, h2Mode) }
519 func testCancelRequestMidBody(t *testing.T, h2 bool) {
520 defer afterTest(t)
521 unblock := make(chan bool)
522 didFlush := make(chan bool, 1)
523 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
524 io.WriteString(w, "Hello")
525 w.(Flusher).Flush()
526 didFlush <- true
527 <-unblock
528 io.WriteString(w, ", world.")
530 defer cst.close()
531 defer close(unblock)
533 req, _ := NewRequest("GET", cst.ts.URL, nil)
534 cancel := make(chan struct{})
535 req.Cancel = cancel
537 res, err := cst.c.Do(req)
538 if err != nil {
539 t.Fatal(err)
541 defer res.Body.Close()
542 <-didFlush
544 // Read a bit before we cancel. (Issue 13626)
545 // We should have "Hello" at least sitting there.
546 firstRead := make([]byte, 10)
547 n, err := res.Body.Read(firstRead)
548 if err != nil {
549 t.Fatal(err)
551 firstRead = firstRead[:n]
553 close(cancel)
555 rest, err := ioutil.ReadAll(res.Body)
556 all := string(firstRead) + string(rest)
557 if all != "Hello" {
558 t.Errorf("Read %q (%q + %q); want Hello", all, firstRead, rest)
560 if !reflect.DeepEqual(err, ExportErrRequestCanceled) {
561 t.Errorf("ReadAll error = %v; want %v", err, ExportErrRequestCanceled)
565 // Tests that clients can send trailers to a server and that the server can read them.
566 func TestTrailersClientToServer_h1(t *testing.T) { testTrailersClientToServer(t, h1Mode) }
567 func TestTrailersClientToServer_h2(t *testing.T) { testTrailersClientToServer(t, h2Mode) }
569 func testTrailersClientToServer(t *testing.T, h2 bool) {
570 defer afterTest(t)
571 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
572 var decl []string
573 for k := range r.Trailer {
574 decl = append(decl, k)
576 sort.Strings(decl)
578 slurp, err := ioutil.ReadAll(r.Body)
579 if err != nil {
580 t.Errorf("Server reading request body: %v", err)
582 if string(slurp) != "foo" {
583 t.Errorf("Server read request body %q; want foo", slurp)
585 if r.Trailer == nil {
586 io.WriteString(w, "nil Trailer")
587 } else {
588 fmt.Fprintf(w, "decl: %v, vals: %s, %s",
589 decl,
590 r.Trailer.Get("Client-Trailer-A"),
591 r.Trailer.Get("Client-Trailer-B"))
594 defer cst.close()
596 var req *Request
597 req, _ = NewRequest("POST", cst.ts.URL, io.MultiReader(
598 eofReaderFunc(func() {
599 req.Trailer["Client-Trailer-A"] = []string{"valuea"}
601 strings.NewReader("foo"),
602 eofReaderFunc(func() {
603 req.Trailer["Client-Trailer-B"] = []string{"valueb"}
606 req.Trailer = Header{
607 "Client-Trailer-A": nil, // to be set later
608 "Client-Trailer-B": nil, // to be set later
610 req.ContentLength = -1
611 res, err := cst.c.Do(req)
612 if err != nil {
613 t.Fatal(err)
615 if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil {
616 t.Error(err)
620 // Tests that servers send trailers to a client and that the client can read them.
621 func TestTrailersServerToClient_h1(t *testing.T) { testTrailersServerToClient(t, h1Mode, false) }
622 func TestTrailersServerToClient_h2(t *testing.T) { testTrailersServerToClient(t, h2Mode, false) }
623 func TestTrailersServerToClient_Flush_h1(t *testing.T) { testTrailersServerToClient(t, h1Mode, true) }
624 func TestTrailersServerToClient_Flush_h2(t *testing.T) { testTrailersServerToClient(t, h2Mode, true) }
626 func testTrailersServerToClient(t *testing.T, h2, flush bool) {
627 defer afterTest(t)
628 const body = "Some body"
629 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
630 w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
631 w.Header().Add("Trailer", "Server-Trailer-C")
633 io.WriteString(w, body)
634 if flush {
635 w.(Flusher).Flush()
638 // How handlers set Trailers: declare it ahead of time
639 // with the Trailer header, and then mutate the
640 // Header() of those values later, after the response
641 // has been written (we wrote to w above).
642 w.Header().Set("Server-Trailer-A", "valuea")
643 w.Header().Set("Server-Trailer-C", "valuec") // skipping B
644 w.Header().Set("Server-Trailer-NotDeclared", "should be omitted")
646 defer cst.close()
648 res, err := cst.c.Get(cst.ts.URL)
649 if err != nil {
650 t.Fatal(err)
653 wantHeader := Header{
654 "Content-Type": {"text/plain; charset=utf-8"},
656 wantLen := -1
657 if h2 && !flush {
658 // In HTTP/1.1, any use of trailers forces HTTP/1.1
659 // chunking and a flush at the first write. That's
660 // unnecessary with HTTP/2's framing, so the server
661 // is able to calculate the length while still sending
662 // trailers afterwards.
663 wantLen = len(body)
664 wantHeader["Content-Length"] = []string{fmt.Sprint(wantLen)}
666 if res.ContentLength != int64(wantLen) {
667 t.Errorf("ContentLength = %v; want %v", res.ContentLength, wantLen)
670 delete(res.Header, "Date") // irrelevant for test
671 if !reflect.DeepEqual(res.Header, wantHeader) {
672 t.Errorf("Header = %v; want %v", res.Header, wantHeader)
675 if got, want := res.Trailer, (Header{
676 "Server-Trailer-A": nil,
677 "Server-Trailer-B": nil,
678 "Server-Trailer-C": nil,
679 }); !reflect.DeepEqual(got, want) {
680 t.Errorf("Trailer before body read = %v; want %v", got, want)
683 if err := wantBody(res, nil, body); err != nil {
684 t.Fatal(err)
687 if got, want := res.Trailer, (Header{
688 "Server-Trailer-A": {"valuea"},
689 "Server-Trailer-B": nil,
690 "Server-Trailer-C": {"valuec"},
691 }); !reflect.DeepEqual(got, want) {
692 t.Errorf("Trailer after body read = %v; want %v", got, want)
696 // Don't allow a Body.Read after Body.Close. Issue 13648.
697 func TestResponseBodyReadAfterClose_h1(t *testing.T) { testResponseBodyReadAfterClose(t, h1Mode) }
698 func TestResponseBodyReadAfterClose_h2(t *testing.T) { testResponseBodyReadAfterClose(t, h2Mode) }
700 func testResponseBodyReadAfterClose(t *testing.T, h2 bool) {
701 defer afterTest(t)
702 const body = "Some body"
703 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
704 io.WriteString(w, body)
706 defer cst.close()
707 res, err := cst.c.Get(cst.ts.URL)
708 if err != nil {
709 t.Fatal(err)
711 res.Body.Close()
712 data, err := ioutil.ReadAll(res.Body)
713 if len(data) != 0 || err == nil {
714 t.Fatalf("ReadAll returned %q, %v; want error", data, err)
718 func TestConcurrentReadWriteReqBody_h1(t *testing.T) { testConcurrentReadWriteReqBody(t, h1Mode) }
719 func TestConcurrentReadWriteReqBody_h2(t *testing.T) { testConcurrentReadWriteReqBody(t, h2Mode) }
720 func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
721 defer afterTest(t)
722 const reqBody = "some request body"
723 const resBody = "some response body"
724 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
725 var wg sync.WaitGroup
726 wg.Add(2)
727 didRead := make(chan bool, 1)
728 // Read in one goroutine.
729 go func() {
730 defer wg.Done()
731 data, err := ioutil.ReadAll(r.Body)
732 if string(data) != reqBody {
733 t.Errorf("Handler read %q; want %q", data, reqBody)
735 if err != nil {
736 t.Errorf("Handler Read: %v", err)
738 didRead <- true
740 // Write in another goroutine.
741 go func() {
742 defer wg.Done()
743 if !h2 {
744 // our HTTP/1 implementation intentionally
745 // doesn't permit writes during read (mostly
746 // due to it being undefined); if that is ever
747 // relaxed, change this.
748 <-didRead
750 io.WriteString(w, resBody)
752 wg.Wait()
754 defer cst.close()
755 req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader(reqBody))
756 req.Header.Add("Expect", "100-continue") // just to complicate things
757 res, err := cst.c.Do(req)
758 if err != nil {
759 t.Fatal(err)
761 data, err := ioutil.ReadAll(res.Body)
762 defer res.Body.Close()
763 if err != nil {
764 t.Fatal(err)
766 if string(data) != resBody {
767 t.Errorf("read %q; want %q", data, resBody)
771 func TestConnectRequest_h1(t *testing.T) { testConnectRequest(t, h1Mode) }
772 func TestConnectRequest_h2(t *testing.T) { testConnectRequest(t, h2Mode) }
773 func testConnectRequest(t *testing.T, h2 bool) {
774 defer afterTest(t)
775 gotc := make(chan *Request, 1)
776 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
777 gotc <- r
779 defer cst.close()
781 u, err := url.Parse(cst.ts.URL)
782 if err != nil {
783 t.Fatal(err)
786 tests := []struct {
787 req *Request
788 want string
791 req: &Request{
792 Method: "CONNECT",
793 Header: Header{},
794 URL: u,
796 want: u.Host,
799 req: &Request{
800 Method: "CONNECT",
801 Header: Header{},
802 URL: u,
803 Host: "example.com:123",
805 want: "example.com:123",
809 for i, tt := range tests {
810 res, err := cst.c.Do(tt.req)
811 if err != nil {
812 t.Errorf("%d. RoundTrip = %v", i, err)
813 continue
815 res.Body.Close()
816 req := <-gotc
817 if req.Method != "CONNECT" {
818 t.Errorf("method = %q; want CONNECT", req.Method)
820 if req.Host != tt.want {
821 t.Errorf("Host = %q; want %q", req.Host, tt.want)
823 if req.URL.Host != tt.want {
824 t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
829 func TestTransportUserAgent_h1(t *testing.T) { testTransportUserAgent(t, h1Mode) }
830 func TestTransportUserAgent_h2(t *testing.T) { testTransportUserAgent(t, h2Mode) }
831 func testTransportUserAgent(t *testing.T, h2 bool) {
832 defer afterTest(t)
833 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
834 fmt.Fprintf(w, "%q", r.Header["User-Agent"])
836 defer cst.close()
838 either := func(a, b string) string {
839 if h2 {
840 return b
842 return a
845 tests := []struct {
846 setup func(*Request)
847 want string
850 func(r *Request) {},
851 either(`["Go-http-client/1.1"]`, `["Go-http-client/2.0"]`),
854 func(r *Request) { r.Header.Set("User-Agent", "foo/1.2.3") },
855 `["foo/1.2.3"]`,
858 func(r *Request) { r.Header["User-Agent"] = []string{"single", "or", "multiple"} },
859 `["single"]`,
862 func(r *Request) { r.Header.Set("User-Agent", "") },
863 `[]`,
866 func(r *Request) { r.Header["User-Agent"] = nil },
867 `[]`,
870 for i, tt := range tests {
871 req, _ := NewRequest("GET", cst.ts.URL, nil)
872 tt.setup(req)
873 res, err := cst.c.Do(req)
874 if err != nil {
875 t.Errorf("%d. RoundTrip = %v", i, err)
876 continue
878 slurp, err := ioutil.ReadAll(res.Body)
879 res.Body.Close()
880 if err != nil {
881 t.Errorf("%d. read body = %v", i, err)
882 continue
884 if string(slurp) != tt.want {
885 t.Errorf("%d. body mismatch.\n got: %s\nwant: %s\n", i, slurp, tt.want)
890 func TestStarRequestFoo_h1(t *testing.T) { testStarRequest(t, "FOO", h1Mode) }
891 func TestStarRequestFoo_h2(t *testing.T) { testStarRequest(t, "FOO", h2Mode) }
892 func TestStarRequestOptions_h1(t *testing.T) { testStarRequest(t, "OPTIONS", h1Mode) }
893 func TestStarRequestOptions_h2(t *testing.T) { testStarRequest(t, "OPTIONS", h2Mode) }
894 func testStarRequest(t *testing.T, method string, h2 bool) {
895 defer afterTest(t)
896 gotc := make(chan *Request, 1)
897 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
898 w.Header().Set("foo", "bar")
899 gotc <- r
900 w.(Flusher).Flush()
902 defer cst.close()
904 u, err := url.Parse(cst.ts.URL)
905 if err != nil {
906 t.Fatal(err)
908 u.Path = "*"
910 req := &Request{
911 Method: method,
912 Header: Header{},
913 URL: u,
916 res, err := cst.c.Do(req)
917 if err != nil {
918 t.Fatalf("RoundTrip = %v", err)
920 res.Body.Close()
922 wantFoo := "bar"
923 wantLen := int64(-1)
924 if method == "OPTIONS" {
925 wantFoo = ""
926 wantLen = 0
928 if res.StatusCode != 200 {
929 t.Errorf("status code = %v; want %d", res.Status, 200)
931 if res.ContentLength != wantLen {
932 t.Errorf("content length = %v; want %d", res.ContentLength, wantLen)
934 if got := res.Header.Get("foo"); got != wantFoo {
935 t.Errorf("response \"foo\" header = %q; want %q", got, wantFoo)
937 select {
938 case req = <-gotc:
939 default:
940 req = nil
942 if req == nil {
943 if method != "OPTIONS" {
944 t.Fatalf("handler never got request")
946 return
948 if req.Method != method {
949 t.Errorf("method = %q; want %q", req.Method, method)
951 if req.URL.Path != "*" {
952 t.Errorf("URL.Path = %q; want *", req.URL.Path)
954 if req.RequestURI != "*" {
955 t.Errorf("RequestURI = %q; want *", req.RequestURI)
959 // Issue 13957
960 func TestTransportDiscardsUnneededConns(t *testing.T) {
961 setParallel(t)
962 defer afterTest(t)
963 cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
964 fmt.Fprintf(w, "Hello, %v", r.RemoteAddr)
966 defer cst.close()
968 var numOpen, numClose int32 // atomic
970 tlsConfig := &tls.Config{InsecureSkipVerify: true}
971 tr := &Transport{
972 TLSClientConfig: tlsConfig,
973 DialTLS: func(_, addr string) (net.Conn, error) {
974 time.Sleep(10 * time.Millisecond)
975 rc, err := net.Dial("tcp", addr)
976 if err != nil {
977 return nil, err
979 atomic.AddInt32(&numOpen, 1)
980 c := noteCloseConn{rc, func() { atomic.AddInt32(&numClose, 1) }}
981 return tls.Client(c, tlsConfig), nil
984 if err := ExportHttp2ConfigureTransport(tr); err != nil {
985 t.Fatal(err)
987 defer tr.CloseIdleConnections()
989 c := &Client{Transport: tr}
991 const N = 10
992 gotBody := make(chan string, N)
993 var wg sync.WaitGroup
994 for i := 0; i < N; i++ {
995 wg.Add(1)
996 go func() {
997 defer wg.Done()
998 resp, err := c.Get(cst.ts.URL)
999 if err != nil {
1000 t.Errorf("Get: %v", err)
1001 return
1003 defer resp.Body.Close()
1004 slurp, err := ioutil.ReadAll(resp.Body)
1005 if err != nil {
1006 t.Error(err)
1008 gotBody <- string(slurp)
1011 wg.Wait()
1012 close(gotBody)
1014 var last string
1015 for got := range gotBody {
1016 if last == "" {
1017 last = got
1018 continue
1020 if got != last {
1021 t.Errorf("Response body changed: %q -> %q", last, got)
1025 var open, close int32
1026 for i := 0; i < 150; i++ {
1027 open, close = atomic.LoadInt32(&numOpen), atomic.LoadInt32(&numClose)
1028 if open < 1 {
1029 t.Fatalf("open = %d; want at least", open)
1031 if close == open-1 {
1032 // Success
1033 return
1035 time.Sleep(10 * time.Millisecond)
1037 t.Errorf("%d connections opened, %d closed; want %d to close", open, close, open-1)
1040 // tests that Transport doesn't retain a pointer to the provided request.
1041 func TestTransportGCRequest_Body_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, true) }
1042 func TestTransportGCRequest_Body_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, true) }
1043 func TestTransportGCRequest_NoBody_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, false) }
1044 func TestTransportGCRequest_NoBody_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, false) }
1045 func testTransportGCRequest(t *testing.T, h2, body bool) {
1046 if runtime.Compiler == "gccgo" {
1047 t.Skip("skipping on gccgo because conservative GC means that finalizer may never run")
1050 setParallel(t)
1051 defer afterTest(t)
1052 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1053 ioutil.ReadAll(r.Body)
1054 if body {
1055 io.WriteString(w, "Hello.")
1058 defer cst.close()
1060 didGC := make(chan struct{})
1061 (func() {
1062 body := strings.NewReader("some body")
1063 req, _ := NewRequest("POST", cst.ts.URL, body)
1064 runtime.SetFinalizer(req, func(*Request) { close(didGC) })
1065 res, err := cst.c.Do(req)
1066 if err != nil {
1067 t.Fatal(err)
1069 if _, err := ioutil.ReadAll(res.Body); err != nil {
1070 t.Fatal(err)
1072 if err := res.Body.Close(); err != nil {
1073 t.Fatal(err)
1075 })()
1076 timeout := time.NewTimer(5 * time.Second)
1077 defer timeout.Stop()
1078 for {
1079 select {
1080 case <-didGC:
1081 return
1082 case <-time.After(100 * time.Millisecond):
1083 runtime.GC()
1084 case <-timeout.C:
1085 t.Fatal("never saw GC of request")
1090 func TestTransportRejectsInvalidHeaders_h1(t *testing.T) {
1091 testTransportRejectsInvalidHeaders(t, h1Mode)
1093 func TestTransportRejectsInvalidHeaders_h2(t *testing.T) {
1094 testTransportRejectsInvalidHeaders(t, h2Mode)
1096 func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
1097 setParallel(t)
1098 defer afterTest(t)
1099 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1100 fmt.Fprintf(w, "Handler saw headers: %q", r.Header)
1101 }), optQuietLog)
1102 defer cst.close()
1103 cst.tr.DisableKeepAlives = true
1105 tests := []struct {
1106 key, val string
1107 ok bool
1109 {"Foo", "capital-key", true}, // verify h2 allows capital keys
1110 {"Foo", "foo\x00bar", false}, // \x00 byte in value not allowed
1111 {"Foo", "two\nlines", false}, // \n byte in value not allowed
1112 {"bogus\nkey", "v", false}, // \n byte also not allowed in key
1113 {"A space", "v", false}, // spaces in keys not allowed
1114 {"имя", "v", false}, // key must be ascii
1115 {"name", "валю", true}, // value may be non-ascii
1116 {"", "v", false}, // key must be non-empty
1117 {"k", "", true}, // value may be empty
1119 for _, tt := range tests {
1120 dialedc := make(chan bool, 1)
1121 cst.tr.Dial = func(netw, addr string) (net.Conn, error) {
1122 dialedc <- true
1123 return net.Dial(netw, addr)
1125 req, _ := NewRequest("GET", cst.ts.URL, nil)
1126 req.Header[tt.key] = []string{tt.val}
1127 res, err := cst.c.Do(req)
1128 var body []byte
1129 if err == nil {
1130 body, _ = ioutil.ReadAll(res.Body)
1131 res.Body.Close()
1133 var dialed bool
1134 select {
1135 case <-dialedc:
1136 dialed = true
1137 default:
1140 if !tt.ok && dialed {
1141 t.Errorf("For key %q, value %q, transport dialed. Expected local failure. Response was: (%v, %v)\nServer replied with: %s", tt.key, tt.val, res, err, body)
1142 } else if (err == nil) != tt.ok {
1143 t.Errorf("For key %q, value %q; got err = %v; want ok=%v", tt.key, tt.val, err, tt.ok)
1148 func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, "boom") }
1149 func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, "boom") }
1150 func TestInterruptWithPanic_nil_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, nil) }
1151 func TestInterruptWithPanic_nil_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, nil) }
1152 func TestInterruptWithPanic_ErrAbortHandler_h1(t *testing.T) {
1153 testInterruptWithPanic(t, h1Mode, ErrAbortHandler)
1155 func TestInterruptWithPanic_ErrAbortHandler_h2(t *testing.T) {
1156 testInterruptWithPanic(t, h2Mode, ErrAbortHandler)
1158 func testInterruptWithPanic(t *testing.T, h2 bool, panicValue interface{}) {
1159 setParallel(t)
1160 const msg = "hello"
1161 defer afterTest(t)
1163 testDone := make(chan struct{})
1164 defer close(testDone)
1166 var errorLog lockedBytesBuffer
1167 gotHeaders := make(chan bool, 1)
1168 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1169 io.WriteString(w, msg)
1170 w.(Flusher).Flush()
1172 select {
1173 case <-gotHeaders:
1174 case <-testDone:
1176 panic(panicValue)
1177 }), func(ts *httptest.Server) {
1178 ts.Config.ErrorLog = log.New(&errorLog, "", 0)
1180 defer cst.close()
1181 res, err := cst.c.Get(cst.ts.URL)
1182 if err != nil {
1183 t.Fatal(err)
1185 gotHeaders <- true
1186 defer res.Body.Close()
1187 slurp, err := ioutil.ReadAll(res.Body)
1188 if string(slurp) != msg {
1189 t.Errorf("client read %q; want %q", slurp, msg)
1191 if err == nil {
1192 t.Errorf("client read all successfully; want some error")
1194 logOutput := func() string {
1195 errorLog.Lock()
1196 defer errorLog.Unlock()
1197 return errorLog.String()
1199 wantStackLogged := panicValue != nil && panicValue != ErrAbortHandler
1201 if err := waitErrCondition(5*time.Second, 10*time.Millisecond, func() error {
1202 gotLog := logOutput()
1203 if !wantStackLogged {
1204 if gotLog == "" {
1205 return nil
1207 return fmt.Errorf("want no log output; got: %s", gotLog)
1209 if gotLog == "" {
1210 return fmt.Errorf("wanted a stack trace logged; got nothing")
1212 if !strings.Contains(gotLog, "created by ") && strings.Count(gotLog, "\n") < 6 {
1213 return fmt.Errorf("output doesn't look like a panic stack trace. Got: %s", gotLog)
1215 return nil
1216 }); err != nil {
1217 t.Fatal(err)
1221 type lockedBytesBuffer struct {
1222 sync.Mutex
1223 bytes.Buffer
1226 func (b *lockedBytesBuffer) Write(p []byte) (int, error) {
1227 b.Lock()
1228 defer b.Unlock()
1229 return b.Buffer.Write(p)
1232 // Issue 15366
1233 func TestH12_AutoGzipWithDumpResponse(t *testing.T) {
1234 h12Compare{
1235 Handler: func(w ResponseWriter, r *Request) {
1236 h := w.Header()
1237 h.Set("Content-Encoding", "gzip")
1238 h.Set("Content-Length", "23")
1239 io.WriteString(w, "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00")
1241 EarlyCheckResponse: func(proto string, res *Response) {
1242 if !res.Uncompressed {
1243 t.Errorf("%s: expected Uncompressed to be set", proto)
1245 dump, err := httputil.DumpResponse(res, true)
1246 if err != nil {
1247 t.Errorf("%s: DumpResponse: %v", proto, err)
1248 return
1250 if strings.Contains(string(dump), "Connection: close") {
1251 t.Errorf("%s: should not see \"Connection: close\" in dump; got:\n%s", proto, dump)
1253 if !strings.Contains(string(dump), "FOO") {
1254 t.Errorf("%s: should see \"FOO\" in response; got:\n%s", proto, dump)
1257 }.run(t)
1260 // Issue 14607
1261 func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) }
1262 func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) }
1263 func testCloseIdleConnections(t *testing.T, h2 bool) {
1264 setParallel(t)
1265 defer afterTest(t)
1266 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1267 w.Header().Set("X-Addr", r.RemoteAddr)
1269 defer cst.close()
1270 get := func() string {
1271 res, err := cst.c.Get(cst.ts.URL)
1272 if err != nil {
1273 t.Fatal(err)
1275 res.Body.Close()
1276 v := res.Header.Get("X-Addr")
1277 if v == "" {
1278 t.Fatal("didn't get X-Addr")
1280 return v
1282 a1 := get()
1283 cst.tr.CloseIdleConnections()
1284 a2 := get()
1285 if a1 == a2 {
1286 t.Errorf("didn't close connection")
1290 type noteCloseConn struct {
1291 net.Conn
1292 closeFunc func()
1295 func (x noteCloseConn) Close() error {
1296 x.closeFunc()
1297 return x.Conn.Close()
1300 type testErrorReader struct{ t *testing.T }
1302 func (r testErrorReader) Read(p []byte) (n int, err error) {
1303 r.t.Error("unexpected Read call")
1304 return 0, io.EOF
1307 func TestNoSniffExpectRequestBody_h1(t *testing.T) { testNoSniffExpectRequestBody(t, h1Mode) }
1308 func TestNoSniffExpectRequestBody_h2(t *testing.T) { testNoSniffExpectRequestBody(t, h2Mode) }
1310 func testNoSniffExpectRequestBody(t *testing.T, h2 bool) {
1311 defer afterTest(t)
1312 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1313 w.WriteHeader(StatusUnauthorized)
1315 defer cst.close()
1317 // Set ExpectContinueTimeout non-zero so RoundTrip won't try to write it.
1318 cst.tr.ExpectContinueTimeout = 10 * time.Second
1320 req, err := NewRequest("POST", cst.ts.URL, testErrorReader{t})
1321 if err != nil {
1322 t.Fatal(err)
1324 req.ContentLength = 0 // so transport is tempted to sniff it
1325 req.Header.Set("Expect", "100-continue")
1326 res, err := cst.tr.RoundTrip(req)
1327 if err != nil {
1328 t.Fatal(err)
1330 defer res.Body.Close()
1331 if res.StatusCode != StatusUnauthorized {
1332 t.Errorf("status code = %v; want %v", res.StatusCode, StatusUnauthorized)
1336 func TestServerUndeclaredTrailers_h1(t *testing.T) { testServerUndeclaredTrailers(t, h1Mode) }
1337 func TestServerUndeclaredTrailers_h2(t *testing.T) { testServerUndeclaredTrailers(t, h2Mode) }
1338 func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
1339 defer afterTest(t)
1340 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1341 w.Header().Set("Foo", "Bar")
1342 w.Header().Set("Trailer:Foo", "Baz")
1343 w.(Flusher).Flush()
1344 w.Header().Add("Trailer:Foo", "Baz2")
1345 w.Header().Set("Trailer:Bar", "Quux")
1347 defer cst.close()
1348 res, err := cst.c.Get(cst.ts.URL)
1349 if err != nil {
1350 t.Fatal(err)
1352 if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
1353 t.Fatal(err)
1355 res.Body.Close()
1356 delete(res.Header, "Date")
1357 delete(res.Header, "Content-Type")
1359 if want := (Header{"Foo": {"Bar"}}); !reflect.DeepEqual(res.Header, want) {
1360 t.Errorf("Header = %#v; want %#v", res.Header, want)
1362 if want := (Header{"Foo": {"Baz", "Baz2"}, "Bar": {"Quux"}}); !reflect.DeepEqual(res.Trailer, want) {
1363 t.Errorf("Trailer = %#v; want %#v", res.Trailer, want)
1367 func TestBadResponseAfterReadingBody(t *testing.T) {
1368 defer afterTest(t)
1369 cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
1370 _, err := io.Copy(ioutil.Discard, r.Body)
1371 if err != nil {
1372 t.Fatal(err)
1374 c, _, err := w.(Hijacker).Hijack()
1375 if err != nil {
1376 t.Fatal(err)
1378 defer c.Close()
1379 fmt.Fprintln(c, "some bogus crap")
1381 defer cst.close()
1383 closes := 0
1384 res, err := cst.c.Post(cst.ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
1385 if err == nil {
1386 res.Body.Close()
1387 t.Fatal("expected an error to be returned from Post")
1389 if closes != 1 {
1390 t.Errorf("closes = %d; want 1", closes)
1394 func TestWriteHeader0_h1(t *testing.T) { testWriteHeader0(t, h1Mode) }
1395 func TestWriteHeader0_h2(t *testing.T) { testWriteHeader0(t, h2Mode) }
1396 func testWriteHeader0(t *testing.T, h2 bool) {
1397 defer afterTest(t)
1398 gotpanic := make(chan bool, 1)
1399 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1400 defer close(gotpanic)
1401 defer func() {
1402 if e := recover(); e != nil {
1403 got := fmt.Sprintf("%T, %v", e, e)
1404 want := "string, invalid WriteHeader code 0"
1405 if got != want {
1406 t.Errorf("unexpected panic value:\n got: %v\nwant: %v\n", got, want)
1408 gotpanic <- true
1410 // Set an explicit 503. This also tests that the WriteHeader call panics
1411 // before it recorded that an explicit value was set and that bogus
1412 // value wasn't stuck.
1413 w.WriteHeader(503)
1416 w.WriteHeader(0)
1418 defer cst.close()
1419 res, err := cst.c.Get(cst.ts.URL)
1420 if err != nil {
1421 t.Fatal(err)
1423 if res.StatusCode != 503 {
1424 t.Errorf("Response: %v %q; want 503", res.StatusCode, res.Status)
1426 if !<-gotpanic {
1427 t.Error("expected panic in handler")
1431 // Issue 23010: don't be super strict checking WriteHeader's code if
1432 // it's not even valid to call WriteHeader then anyway.
1433 func TestWriteHeaderNoCodeCheck_h1(t *testing.T) { testWriteHeaderAfterWrite(t, h1Mode, false) }
1434 func TestWriteHeaderNoCodeCheck_h1hijack(t *testing.T) { testWriteHeaderAfterWrite(t, h1Mode, true) }
1435 func TestWriteHeaderNoCodeCheck_h2(t *testing.T) { testWriteHeaderAfterWrite(t, h2Mode, false) }
1436 func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
1437 setParallel(t)
1438 defer afterTest(t)
1440 var errorLog lockedBytesBuffer
1441 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
1442 if hijack {
1443 conn, _, _ := w.(Hijacker).Hijack()
1444 defer conn.Close()
1445 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nfoo"))
1446 w.WriteHeader(0) // verify this doesn't panic if there's already output; Issue 23010
1447 conn.Write([]byte("bar"))
1448 return
1450 io.WriteString(w, "foo")
1451 w.(Flusher).Flush()
1452 w.WriteHeader(0) // verify this doesn't panic if there's already output; Issue 23010
1453 io.WriteString(w, "bar")
1454 }), func(ts *httptest.Server) {
1455 ts.Config.ErrorLog = log.New(&errorLog, "", 0)
1457 defer cst.close()
1458 res, err := cst.c.Get(cst.ts.URL)
1459 if err != nil {
1460 t.Fatal(err)
1462 defer res.Body.Close()
1463 body, err := ioutil.ReadAll(res.Body)
1464 if err != nil {
1465 t.Fatal(err)
1467 if got, want := string(body), "foobar"; got != want {
1468 t.Errorf("got = %q; want %q", got, want)
1471 // Also check the stderr output:
1472 if h2 {
1473 // TODO: also emit this log message for HTTP/2?
1474 // We historically haven't, so don't check.
1475 return
1477 gotLog := strings.TrimSpace(errorLog.String())
1478 wantLog := "http: multiple response.WriteHeader calls"
1479 if hijack {
1480 wantLog = "http: response.WriteHeader on hijacked connection"
1482 if gotLog != wantLog {
1483 t.Errorf("stderr output = %q; want %q", gotLog, wantLog)