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.
33 type clientServerTest
struct {
42 func (t
*clientServerTest
) close() {
43 t
.tr
.CloseIdleConnections()
47 func (t
*clientServerTest
) getURL(u
string) string {
48 res
, err
:= t
.c
.Get(u
)
52 defer res
.Body
.Close()
53 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
60 func (t
*clientServerTest
) scheme() string {
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
{
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
):
90 case func(*httptest
.Server
):
93 t
.Fatalf("unhandled option type %T", opt
)
101 ExportHttp2ConfigureServer(cst
.ts
.Config
, nil)
102 cst
.ts
.TLS
= cst
.ts
.Config
.TLSConfig
105 cst
.tr
.TLSClientConfig
= &tls
.Config
{
106 InsecureSkipVerify
: true,
108 if err
:= ExportHttp2ConfigureTransport(cst
.tr
); err
!= nil {
114 // Testing the newClientServerTest helper itself.
115 func TestNewClientServerTest(t
*testing
.T
) {
120 h
:= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
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 {
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) {
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
148 fmt
.Fprintf(w
, "I am a chunked response.")
152 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
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"}
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
184 func (tt h12Compare
) reqFunc() reqFunc
{
185 if tt
.ReqFunc
== nil {
191 func (tt h12Compare
) run(t
*testing
.T
) {
193 cst1
:= newClientServerTest(t
, false, HandlerFunc(tt
.Handler
), tt
.Opts
...)
195 cst2
:= newClientServerTest(t
, true, HandlerFunc(tt
.Handler
), tt
.Opts
...)
198 res1
, err
:= tt
.reqFunc()(cst1
.c
, cst1
.ts
.URL
)
200 t
.Errorf("HTTP/1 request: %v", err
)
203 res2
, err
:= tt
.reqFunc()(cst2
.c
, cst2
.ts
.URL
)
205 t
.Errorf("HTTP/2 request: %v", err
)
209 if fn
:= tt
.EarlyCheckResponse
; fn
!= nil {
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
234 func mostlyCopy(r
*Response
) *Response
{
237 c
.TransferEncoding
= nil
243 type slurpResult
struct {
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
255 t
.Errorf("got %q response; want %q", res
.Proto
, wantProto
)
257 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
260 res
.Body
= slurpResult
{
261 ReadCloser
: ioutil
.NopCloser(bytes
.NewReader(slurp
)),
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)
277 func TestH12_HeadContentLengthNoBody(t
*testing
.T
) {
279 ReqFunc
: (*Client
).Head
,
280 Handler
: func(w ResponseWriter
, r
*Request
) {
285 func TestH12_HeadContentLengthSmallBody(t
*testing
.T
) {
287 ReqFunc
: (*Client
).Head
,
288 Handler
: func(w ResponseWriter
, r
*Request
) {
289 io
.WriteString(w
, "small")
294 func TestH12_HeadContentLengthLargeBody(t
*testing
.T
) {
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
)
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
)
320 func TestH12_SmallBody(t
*testing
.T
) {
321 h12Compare
{Handler
: func(w ResponseWriter
, r
*Request
) {
322 io
.WriteString(w
, "small body")
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")
333 func TestH12_FlushBeforeBody(t
*testing
.T
) {
334 h12Compare
{Handler
: func(w ResponseWriter
, r
*Request
) {
336 io
.WriteString(w
, "foo")
340 func TestH12_FlushMidBody(t
*testing
.T
) {
341 h12Compare
{Handler
: func(w ResponseWriter
, r
*Request
) {
342 io
.WriteString(w
, "foo")
344 io
.WriteString(w
, "bar")
348 func TestH12_Head_ExplicitLen(t
*testing
.T
) {
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")
360 func TestH12_Head_ImplicitLen(t
*testing
.T
) {
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")
372 func TestH12_HandlerWritesTooLittle(t
*testing
.T
) {
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
)
381 t
.Errorf("%s body is %T; want slurpResult", proto
, res
.Body
)
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")
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
400 func TestH12_HandlerWritesTooMuch(t
*testing
.T
) {
402 Handler
: func(w ResponseWriter
, r
*Request
) {
403 w
.Header().Set("Content-Length", "3")
405 io
.WriteString(w
, "123")
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
)
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
) {
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.")
431 func TestH12_AutoGzip_Disabled(t
*testing
.T
) {
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
)
445 // Test304Responses verifies that 304s don't declare that they're
446 // chunking in their response headers and aren't allowed to produce
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) {
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
)
461 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
465 if len(res
.TransferEncoding
) > 0 {
466 t
.Errorf("expected no TransferEncoding; got %v", res
.TransferEncoding
)
468 body
, err
:= ioutil
.ReadAll(res
.Body
)
473 t
.Errorf("got unexpected body %q", string(body
))
477 func TestH12_ServerEmptyContentLength(t
*testing
.T
) {
479 Handler
: func(w ResponseWriter
, r
*Request
) {
480 w
.Header()["Content-Type"] = []string{""}
481 io
.WriteString(w
, "<html><body>hi</body></html>")
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) {
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
)
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) {
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")
528 io
.WriteString(w
, ", world.")
533 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
534 cancel
:= make(chan struct{})
537 res
, err
:= cst
.c
.Do(req
)
541 defer res
.Body
.Close()
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
)
551 firstRead
= firstRead
[:n
]
555 rest
, err
:= ioutil
.ReadAll(res
.Body
)
556 all
:= string(firstRead
) + string(rest
)
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) {
571 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
573 for k
:= range r
.Trailer
{
574 decl
= append(decl
, k
)
578 slurp
, err
:= ioutil
.ReadAll(r
.Body
)
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")
588 fmt
.Fprintf(w
, "decl: %v, vals: %s, %s",
590 r
.Trailer
.Get("Client-Trailer-A"),
591 r
.Trailer
.Get("Client-Trailer-B"))
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
)
615 if err
:= wantBody(res
, err
, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err
!= nil {
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) {
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
)
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")
648 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
653 wantHeader
:= Header
{
654 "Content-Type": {"text/plain; charset=utf-8"},
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.
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 {
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) {
702 const body
= "Some body"
703 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
704 io
.WriteString(w
, body
)
707 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
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) {
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
727 didRead
:= make(chan bool, 1)
728 // Read in one goroutine.
731 data
, err
:= ioutil
.ReadAll(r
.Body
)
732 if string(data
) != reqBody
{
733 t
.Errorf("Handler read %q; want %q", data
, reqBody
)
736 t
.Errorf("Handler Read: %v", err
)
740 // Write in another goroutine.
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.
750 io
.WriteString(w
, resBody
)
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
)
761 data
, err
:= ioutil
.ReadAll(res
.Body
)
762 defer res
.Body
.Close()
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) {
775 gotc
:= make(chan *Request
, 1)
776 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
781 u
, err
:= url
.Parse(cst
.ts
.URL
)
803 Host
: "example.com:123",
805 want
: "example.com:123",
809 for i
, tt
:= range tests
{
810 res
, err
:= cst
.c
.Do(tt
.req
)
812 t
.Errorf("%d. RoundTrip = %v", i
, err
)
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) {
833 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
834 fmt
.Fprintf(w
, "%q", r
.Header
["User-Agent"])
838 either
:= func(a
, b
string) string {
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") },
858 func(r
*Request
) { r
.Header
["User-Agent"] = []string{"single", "or", "multiple"} },
862 func(r
*Request
) { r
.Header
.Set("User-Agent", "") },
866 func(r
*Request
) { r
.Header
["User-Agent"] = nil },
870 for i
, tt
:= range tests
{
871 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
873 res
, err
:= cst
.c
.Do(req
)
875 t
.Errorf("%d. RoundTrip = %v", i
, err
)
878 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
881 t
.Errorf("%d. read body = %v", i
, err
)
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) {
896 gotc
:= make(chan *Request
, 1)
897 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
898 w
.Header().Set("foo", "bar")
904 u
, err
:= url
.Parse(cst
.ts
.URL
)
916 res
, err
:= cst
.c
.Do(req
)
918 t
.Fatalf("RoundTrip = %v", err
)
924 if method
== "OPTIONS" {
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
)
943 if method
!= "OPTIONS" {
944 t
.Fatalf("handler never got request")
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
)
960 func TestTransportDiscardsUnneededConns(t
*testing
.T
) {
963 cst
:= newClientServerTest(t
, h2Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
964 fmt
.Fprintf(w
, "Hello, %v", r
.RemoteAddr
)
968 var numOpen
, numClose
int32 // atomic
970 tlsConfig
:= &tls
.Config
{InsecureSkipVerify
: true}
972 TLSClientConfig
: tlsConfig
,
973 DialTLS
: func(_
, addr
string) (net
.Conn
, error
) {
974 time
.Sleep(10 * time
.Millisecond
)
975 rc
, err
:= net
.Dial("tcp", addr
)
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 {
987 defer tr
.CloseIdleConnections()
989 c
:= &Client
{Transport
: tr
}
992 gotBody
:= make(chan string, N
)
993 var wg sync
.WaitGroup
994 for i
:= 0; i
< N
; i
++ {
998 resp
, err
:= c
.Get(cst
.ts
.URL
)
1000 t
.Errorf("Get: %v", err
)
1003 defer resp
.Body
.Close()
1004 slurp
, err
:= ioutil
.ReadAll(resp
.Body
)
1008 gotBody
<- string(slurp
)
1015 for got
:= range gotBody
{
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
)
1029 t
.Fatalf("open = %d; want at least", open
)
1031 if close == open
-1 {
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")
1052 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1053 ioutil
.ReadAll(r
.Body
)
1055 io
.WriteString(w
, "Hello.")
1060 didGC
:= make(chan struct{})
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
)
1069 if _
, err
:= ioutil
.ReadAll(res
.Body
); err
!= nil {
1072 if err
:= res
.Body
.Close(); err
!= nil {
1076 timeout
:= time
.NewTimer(5 * time
.Second
)
1077 defer timeout
.Stop()
1082 case <-time
.After(100 * time
.Millisecond
):
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) {
1099 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1100 fmt
.Fprintf(w
, "Handler saw headers: %q", r
.Header
)
1103 cst
.tr
.DisableKeepAlives
= true
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
) {
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
)
1130 body
, _
= ioutil
.ReadAll(res
.Body
)
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{}) {
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
)
1177 }), func(ts
*httptest
.Server
) {
1178 ts
.Config
.ErrorLog
= log
.New(&errorLog
, "", 0)
1181 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
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
)
1192 t
.Errorf("client read all successfully; want some error")
1194 logOutput
:= func() string {
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
{
1207 return fmt
.Errorf("want no log output; got: %s", 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
)
1221 type lockedBytesBuffer
struct {
1226 func (b
*lockedBytesBuffer
) Write(p
[]byte) (int, error
) {
1229 return b
.Buffer
.Write(p
)
1233 func TestH12_AutoGzipWithDumpResponse(t
*testing
.T
) {
1235 Handler
: func(w ResponseWriter
, r
*Request
) {
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)
1247 t
.Errorf("%s: DumpResponse: %v", proto
, err
)
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
)
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) {
1266 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1267 w
.Header().Set("X-Addr", r
.RemoteAddr
)
1270 get
:= func() string {
1271 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1276 v
:= res
.Header
.Get("X-Addr")
1278 t
.Fatal("didn't get X-Addr")
1283 cst
.tr
.CloseIdleConnections()
1286 t
.Errorf("didn't close connection")
1290 type noteCloseConn
struct {
1295 func (x noteCloseConn
) Close() error
{
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")
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) {
1312 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1313 w
.WriteHeader(StatusUnauthorized
)
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
})
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
)
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) {
1340 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1341 w
.Header().Set("Foo", "Bar")
1342 w
.Header().Set("Trailer:Foo", "Baz")
1344 w
.Header().Add("Trailer:Foo", "Baz2")
1345 w
.Header().Set("Trailer:Bar", "Quux")
1348 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1352 if _
, err
:= io
.Copy(ioutil
.Discard
, res
.Body
); err
!= nil {
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
) {
1369 cst
:= newClientServerTest(t
, false, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1370 _
, err
:= io
.Copy(ioutil
.Discard
, r
.Body
)
1374 c
, _
, err
:= w
.(Hijacker
).Hijack()
1379 fmt
.Fprintln(c
, "some bogus crap")
1384 res
, err
:= cst
.c
.Post(cst
.ts
.URL
, "text/plain", countCloseReader
{&closes
, strings
.NewReader("hello")})
1387 t
.Fatal("expected an error to be returned from Post")
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) {
1398 gotpanic
:= make(chan bool, 1)
1399 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1400 defer close(gotpanic
)
1402 if e
:= recover(); e
!= nil {
1403 got
:= fmt
.Sprintf("%T, %v", e
, e
)
1404 want
:= "string, invalid WriteHeader code 0"
1406 t
.Errorf("unexpected panic value:\n got: %v\nwant: %v\n", got
, want
)
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.
1419 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1423 if res
.StatusCode
!= 503 {
1424 t
.Errorf("Response: %v %q; want 503", res
.StatusCode
, res
.Status
)
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) {
1440 var errorLog lockedBytesBuffer
1441 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1443 conn
, _
, _
:= w
.(Hijacker
).Hijack()
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"))
1450 io
.WriteString(w
, "foo")
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)
1458 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1462 defer res
.Body
.Close()
1463 body
, err
:= ioutil
.ReadAll(res
.Body
)
1467 if got
, want
:= string(body
), "foobar"; got
!= want
{
1468 t
.Errorf("got = %q; want %q", got
, want
)
1471 // Also check the stderr output:
1473 // TODO: also emit this log message for HTTP/2?
1474 // We historically haven't, so don't check.
1477 gotLog
:= strings
.TrimSpace(errorLog
.String())
1478 wantLog
:= "http: multiple response.WriteHeader calls"
1480 wantLog
= "http: response.WriteHeader on hijacked connection"
1482 if gotLog
!= wantLog
{
1483 t
.Errorf("stderr output = %q; want %q", gotLog
, wantLog
)