blob: e1274b0ae26f611722b3cd725abbc3493d6d2688 [file] [log] [blame]
Andrew Gerrand6d10a0c2015-10-14 04:11:41 +00001// 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.
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +00004
5package http2
6
7import (
Brad Fitzpatrick438097d2015-12-01 22:16:42 +00008 "bufio"
9 "bytes"
Blake Mizeranye1a58162015-10-24 16:42:11 -070010 "crypto/tls"
Brad Fitzpatrick438097d2015-12-01 22:16:42 +000011 "errors"
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000012 "flag"
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +000013 "fmt"
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -080014 "io"
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -080015 "io/ioutil"
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +000016 "math/rand"
Blake Mizeranye1a58162015-10-24 16:42:11 -070017 "net"
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000018 "net/http"
Blake Mizeranyce84af22015-10-27 23:17:12 -070019 "net/url"
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000020 "os"
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -080021 "reflect"
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +000022 "runtime"
Brad Fitzpatrick493a2622016-02-04 19:41:12 +000023 "sort"
Brad Fitzpatrick438097d2015-12-01 22:16:42 +000024 "strconv"
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -080025 "strings"
Blake Mizeranye1a58162015-10-24 16:42:11 -070026 "sync"
Brad Fitzpatrick438097d2015-12-01 22:16:42 +000027 "sync/atomic"
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000028 "testing"
Blake Mizerany35769072015-02-08 22:09:17 -080029 "time"
Brad Fitzpatrick438097d2015-12-01 22:16:42 +000030
31 "golang.org/x/net/http2/hpack"
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000032)
33
Brad Fitzpatrick07ee6802015-02-03 12:57:45 +000034var (
35 extNet = flag.Bool("extnet", false, "do external network tests")
36 transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport")
Blake Mizerany1b277612015-10-27 22:40:40 -070037 insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove?
Brad Fitzpatrick07ee6802015-02-03 12:57:45 +000038)
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000039
Blake Mizeranye1a58162015-10-24 16:42:11 -070040var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true}
41
Brad Fitzpatrickd3b63542015-02-08 17:02:49 -080042func TestTransportExternal(t *testing.T) {
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000043 if !*extNet {
44 t.Skip("skipping external network test")
45 }
Brad Fitzpatrick07ee6802015-02-03 12:57:45 +000046 req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil)
Blake Mizeranye1a58162015-10-24 16:42:11 -070047 rt := &Transport{TLSClientConfig: tlsConfigInsecure}
Brad Fitzpatrickfcb18db2015-02-02 15:41:30 +000048 res, err := rt.RoundTrip(req)
49 if err != nil {
50 t.Fatalf("%v", err)
51 }
52 res.Write(os.Stdout)
53}
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -080054
ayanamistb3e9c8f2016-05-18 06:54:12 +080055func startH2cServer(t *testing.T) net.Listener {
56 h2Server := &Server{}
57 l := newLocalListener(t)
58 go func() {
59 conn, err := l.Accept()
60 if err != nil {
61 t.Error(err)
62 return
63 }
64 h2Server.ServeConn(conn, &ServeConnOpts{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
65 fmt.Fprintf(w, "Hello, %v", r.URL.Path)
66 })})
67 }()
68 return l
69}
70
71func TestTransportH2c(t *testing.T) {
72 l := startH2cServer(t)
73 defer l.Close()
74 req, err := http.NewRequest("GET", "http://"+l.Addr().String()+"/foobar", nil)
75 if err != nil {
76 t.Fatal(err)
77 }
78 tr := &Transport{
79 AllowHTTP: true,
80 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
81 return net.Dial(network, addr)
82 },
83 }
84 res, err := tr.RoundTrip(req)
85 if err != nil {
86 t.Fatal(err)
87 }
88 if res.ProtoMajor != 2 {
89 t.Fatal("proto not h2c")
90 }
91 body, err := ioutil.ReadAll(res.Body)
92 if err != nil {
93 t.Fatal(err)
94 }
95 if got, want := string(body), "Hello, /foobar"; got != want {
96 t.Fatalf("response got %v, want %v", got, want)
97 }
98}
99
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800100func TestTransport(t *testing.T) {
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800101 const body = "sup"
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800102 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800103 io.WriteString(w, body)
Brad Fitzpatrickcd8c2702015-10-15 20:01:14 +0000104 }, optOnlyServer)
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800105 defer st.Close()
106
Blake Mizeranye1a58162015-10-24 16:42:11 -0700107 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800108 defer tr.CloseIdleConnections()
109
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800110 req, err := http.NewRequest("GET", st.ts.URL, nil)
111 if err != nil {
112 t.Fatal(err)
113 }
114 res, err := tr.RoundTrip(req)
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800115 if err != nil {
116 t.Fatal(err)
117 }
118 defer res.Body.Close()
119
120 t.Logf("Got res: %+v", res)
121 if g, w := res.StatusCode, 200; g != w {
122 t.Errorf("StatusCode = %v; want %v", g, w)
123 }
124 if g, w := res.Status, "200 OK"; g != w {
125 t.Errorf("Status = %q; want %q", g, w)
126 }
127 wantHeader := http.Header{
128 "Content-Length": []string{"3"},
129 "Content-Type": []string{"text/plain; charset=utf-8"},
Brad Fitzpatrickc745c362015-11-24 17:14:16 -0800130 "Date": []string{"XXX"}, // see cleanDate
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800131 }
Brad Fitzpatrickc745c362015-11-24 17:14:16 -0800132 cleanDate(res)
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800133 if !reflect.DeepEqual(res.Header, wantHeader) {
134 t.Errorf("res Header = %v; want %v", res.Header, wantHeader)
135 }
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800136 if res.Request != req {
137 t.Errorf("Response.Request = %p; want %p", res.Request, req)
138 }
139 if res.TLS == nil {
Matt Layher6c53fec2015-05-03 16:39:16 -0400140 t.Error("Response.TLS = nil; want non-nil")
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800141 }
142 slurp, err := ioutil.ReadAll(res.Body)
143 if err != nil {
Matt Layher6c53fec2015-05-03 16:39:16 -0400144 t.Errorf("Body read: %v", err)
Brad Fitzpatrickb4eaf1c2015-02-08 17:52:35 -0800145 } else if string(slurp) != body {
146 t.Errorf("Body = %q; want %q", slurp, body)
147 }
Brad Fitzpatrickebe9b942015-02-08 17:23:16 -0800148}
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +0000149
Brad Fitzpatrick493a2622016-02-04 19:41:12 +0000150func onSameConn(t *testing.T, modReq func(*http.Request)) bool {
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800151 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
152 io.WriteString(w, r.RemoteAddr)
153 }, optOnlyServer)
154 defer st.Close()
Blake Mizeranye1a58162015-10-24 16:42:11 -0700155 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800156 defer tr.CloseIdleConnections()
157 get := func() string {
158 req, err := http.NewRequest("GET", st.ts.URL, nil)
159 if err != nil {
160 t.Fatal(err)
161 }
Brad Fitzpatrick493a2622016-02-04 19:41:12 +0000162 modReq(req)
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800163 res, err := tr.RoundTrip(req)
164 if err != nil {
165 t.Fatal(err)
166 }
167 defer res.Body.Close()
168 slurp, err := ioutil.ReadAll(res.Body)
169 if err != nil {
170 t.Fatalf("Body read: %v", err)
171 }
172 addr := strings.TrimSpace(string(slurp))
173 if addr == "" {
174 t.Fatalf("didn't get an addr in response")
175 }
176 return addr
177 }
178 first := get()
179 second := get()
Brad Fitzpatrick493a2622016-02-04 19:41:12 +0000180 return first == second
181}
182
183func TestTransportReusesConns(t *testing.T) {
184 if !onSameConn(t, func(*http.Request) {}) {
185 t.Errorf("first and second responses were on different connections")
186 }
187}
188
189func TestTransportReusesConn_RequestClose(t *testing.T) {
190 if onSameConn(t, func(r *http.Request) { r.Close = true }) {
191 t.Errorf("first and second responses were not on different connections")
192 }
193}
194
195func TestTransportReusesConn_ConnClose(t *testing.T) {
196 if onSameConn(t, func(r *http.Request) { r.Header.Set("Connection", "close") }) {
197 t.Errorf("first and second responses were not on different connections")
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800198 }
199}
Blake Mizerany35769072015-02-08 22:09:17 -0800200
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000201// Tests that the Transport only keeps one pending dial open per destination address.
202// https://golang.org/issue/13397
203func TestTransportGroupsPendingDials(t *testing.T) {
204 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
205 io.WriteString(w, r.RemoteAddr)
206 }, optOnlyServer)
207 defer st.Close()
208 tr := &Transport{
209 TLSClientConfig: tlsConfigInsecure,
210 }
211 defer tr.CloseIdleConnections()
212 var (
213 mu sync.Mutex
214 dials = map[string]int{}
215 )
216 var wg sync.WaitGroup
217 for i := 0; i < 10; i++ {
218 wg.Add(1)
219 go func() {
220 defer wg.Done()
221 req, err := http.NewRequest("GET", st.ts.URL, nil)
222 if err != nil {
223 t.Error(err)
224 return
225 }
226 res, err := tr.RoundTrip(req)
227 if err != nil {
228 t.Error(err)
229 return
230 }
231 defer res.Body.Close()
232 slurp, err := ioutil.ReadAll(res.Body)
233 if err != nil {
234 t.Errorf("Body read: %v", err)
235 }
236 addr := strings.TrimSpace(string(slurp))
237 if addr == "" {
238 t.Errorf("didn't get an addr in response")
239 }
240 mu.Lock()
241 dials[addr]++
242 mu.Unlock()
243 }()
244 }
245 wg.Wait()
246 if len(dials) != 1 {
247 t.Errorf("saw %d dials; want 1: %v", len(dials), dials)
248 }
249 tr.CloseIdleConnections()
250 if err := retry(50, 10*time.Millisecond, func() error {
251 cp, ok := tr.connPool().(*clientConnPool)
252 if !ok {
253 return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool())
254 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000255 cp.mu.Lock()
256 defer cp.mu.Unlock()
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000257 if len(cp.dialing) != 0 {
258 return fmt.Errorf("dialing map = %v; want empty", cp.dialing)
259 }
260 if len(cp.conns) != 0 {
261 return fmt.Errorf("conns = %v; want empty", cp.conns)
262 }
263 if len(cp.keys) != 0 {
264 return fmt.Errorf("keys = %v; want empty", cp.keys)
265 }
266 return nil
267 }); err != nil {
Mikio Hara1d7a0b22016-01-07 09:41:45 +0900268 t.Errorf("State of pool after CloseIdleConnections: %v", err)
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000269 }
270}
271
272func retry(tries int, delay time.Duration, fn func() error) error {
273 var err error
274 for i := 0; i < tries; i++ {
275 err = fn()
276 if err == nil {
277 return nil
278 }
279 time.Sleep(delay)
280 }
281 return err
282}
283
Blake Mizerany35769072015-02-08 22:09:17 -0800284func TestTransportAbortClosesPipes(t *testing.T) {
285 shutdown := make(chan struct{})
286 st := newServerTester(t,
287 func(w http.ResponseWriter, r *http.Request) {
288 w.(http.Flusher).Flush()
289 <-shutdown
290 },
291 optOnlyServer,
292 )
293 defer st.Close()
294 defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
295
296 done := make(chan struct{})
297 requestMade := make(chan struct{})
298 go func() {
299 defer close(done)
Blake Mizeranye1a58162015-10-24 16:42:11 -0700300 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
Blake Mizerany35769072015-02-08 22:09:17 -0800301 req, err := http.NewRequest("GET", st.ts.URL, nil)
302 if err != nil {
303 t.Fatal(err)
304 }
305 res, err := tr.RoundTrip(req)
306 if err != nil {
307 t.Fatal(err)
308 }
309 defer res.Body.Close()
310 close(requestMade)
311 _, err = ioutil.ReadAll(res.Body)
312 if err == nil {
313 t.Error("expected error from res.Body.Read")
314 }
315 }()
316
317 <-requestMade
318 // Now force the serve loop to end, via closing the connection.
319 st.closeConn()
320 // deadlock? that's a bug.
321 select {
322 case <-done:
323 case <-time.After(3 * time.Second):
324 t.Fatal("timeout")
325 }
326}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500327
Blake Mizeranyce84af22015-10-27 23:17:12 -0700328// TODO: merge this with TestTransportBody to make TestTransportRequest? This
329// could be a table-driven test with extra goodies.
330func TestTransportPath(t *testing.T) {
331 gotc := make(chan *url.URL, 1)
332 st := newServerTester(t,
333 func(w http.ResponseWriter, r *http.Request) {
334 gotc <- r.URL
335 },
336 optOnlyServer,
337 )
338 defer st.Close()
339
340 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
341 defer tr.CloseIdleConnections()
342 const (
343 path = "/testpath"
344 query = "q=1"
345 )
346 surl := st.ts.URL + path + "?" + query
347 req, err := http.NewRequest("POST", surl, nil)
348 if err != nil {
349 t.Fatal(err)
350 }
351 c := &http.Client{Transport: tr}
352 res, err := c.Do(req)
353 if err != nil {
354 t.Fatal(err)
355 }
356 defer res.Body.Close()
357 got := <-gotc
358 if got.Path != path {
359 t.Errorf("Read Path = %q; want %q", got.Path, path)
360 }
361 if got.RawQuery != query {
362 t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
363 }
364}
365
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000366func randString(n int) string {
367 rnd := rand.New(rand.NewSource(int64(n)))
368 b := make([]byte, n)
369 for i := range b {
370 b[i] = byte(rnd.Intn(256))
371 }
372 return string(b)
373}
374
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500375func TestTransportBody(t *testing.T) {
Brad Fitzpatrick4d06dbd2016-03-21 23:17:53 +0000376 bodyTests := []struct {
377 body string
378 noContentLen bool
379 }{
380 {body: "some message"},
381 {body: "some message", noContentLen: true},
382 {body: ""},
383 {body: "", noContentLen: true},
384 {body: strings.Repeat("a", 1<<20), noContentLen: true},
385 {body: strings.Repeat("a", 1<<20)},
386 {body: randString(16<<10 - 1)},
387 {body: randString(16 << 10)},
388 {body: randString(16<<10 + 1)},
389 {body: randString(512<<10 - 1)},
390 {body: randString(512 << 10)},
391 {body: randString(512<<10 + 1)},
392 {body: randString(1<<20 - 1)},
393 {body: randString(1 << 20)},
394 {body: randString(1<<20 + 2)},
395 }
396
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800397 type reqInfo struct {
398 req *http.Request
399 slurp []byte
400 err error
401 }
402 gotc := make(chan reqInfo, 1)
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500403 st := newServerTester(t,
404 func(w http.ResponseWriter, r *http.Request) {
405 slurp, err := ioutil.ReadAll(r.Body)
406 if err != nil {
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800407 gotc <- reqInfo{err: err}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500408 } else {
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800409 gotc <- reqInfo{req: r, slurp: slurp}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500410 }
411 },
412 optOnlyServer,
413 )
414 defer st.Close()
415
Blake Mizerany1b277612015-10-27 22:40:40 -0700416 for i, tt := range bodyTests {
417 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
418 defer tr.CloseIdleConnections()
419
420 var body io.Reader = strings.NewReader(tt.body)
421 if tt.noContentLen {
422 body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
423 }
424 req, err := http.NewRequest("POST", st.ts.URL, body)
425 if err != nil {
426 t.Fatalf("#%d: %v", i, err)
427 }
428 c := &http.Client{Transport: tr}
429 res, err := c.Do(req)
430 if err != nil {
431 t.Fatalf("#%d: %v", i, err)
432 }
433 defer res.Body.Close()
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800434 ri := <-gotc
435 if ri.err != nil {
Mikio Hara7f882712016-02-05 10:48:01 +0900436 t.Errorf("#%d: read error: %v", i, ri.err)
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800437 continue
438 }
439 if got := string(ri.slurp); got != tt.body {
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000440 t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body))
Blake Mizerany1b277612015-10-27 22:40:40 -0700441 }
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800442 wantLen := int64(len(tt.body))
443 if tt.noContentLen && tt.body != "" {
444 wantLen = -1
445 }
446 if ri.req.ContentLength != wantLen {
447 t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen)
448 }
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500449 }
450}
Blake Mizeranye1a58162015-10-24 16:42:11 -0700451
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000452func shortString(v string) string {
453 const maxLen = 100
454 if len(v) <= maxLen {
455 return v
456 }
457 return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
458}
459
Blake Mizeranye1a58162015-10-24 16:42:11 -0700460func TestTransportDialTLS(t *testing.T) {
461 var mu sync.Mutex // guards following
462 var gotReq, didDial bool
463
464 ts := newServerTester(t,
465 func(w http.ResponseWriter, r *http.Request) {
466 mu.Lock()
467 gotReq = true
468 mu.Unlock()
469 },
470 optOnlyServer,
471 )
472 defer ts.Close()
473 tr := &Transport{
474 DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
475 mu.Lock()
476 didDial = true
477 mu.Unlock()
478 cfg.InsecureSkipVerify = true
479 c, err := tls.Dial(netw, addr, cfg)
480 if err != nil {
481 return nil, err
482 }
483 return c, c.Handshake()
484 },
485 }
486 defer tr.CloseIdleConnections()
487 client := &http.Client{Transport: tr}
488 res, err := client.Get(ts.ts.URL)
489 if err != nil {
490 t.Fatal(err)
491 }
492 res.Body.Close()
493 mu.Lock()
494 if !gotReq {
495 t.Error("didn't get request")
496 }
497 if !didDial {
498 t.Error("didn't use dial hook")
499 }
500}
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100501
502func TestConfigureTransport(t *testing.T) {
503 t1 := &http.Transport{}
504 err := ConfigureTransport(t1)
505 if err == errTransportVersion {
506 t.Skip(err)
507 }
508 if err != nil {
509 t.Fatal(err)
510 }
511 if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) {
512 // Laziness, to avoid buildtags.
513 t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got)
514 }
Brad Fitzpatrickb304fd02015-12-14 17:57:33 +0000515 wantNextProtos := []string{"h2", "http/1.1"}
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100516 if t1.TLSClientConfig == nil {
517 t.Errorf("nil t1.TLSClientConfig")
Brad Fitzpatrickb304fd02015-12-14 17:57:33 +0000518 } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) {
519 t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos)
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100520 }
521 if err := ConfigureTransport(t1); err == nil {
522 t.Error("unexpected success on second call to ConfigureTransport")
523 }
524
525 // And does it work?
526 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
527 io.WriteString(w, r.Proto)
528 }, optOnlyServer)
529 defer st.Close()
530
531 t1.TLSClientConfig.InsecureSkipVerify = true
532 c := &http.Client{Transport: t1}
533 res, err := c.Get(st.ts.URL)
534 if err != nil {
535 t.Fatal(err)
536 }
537 slurp, err := ioutil.ReadAll(res.Body)
538 if err != nil {
539 t.Fatal(err)
540 }
541 if got, want := string(slurp), "HTTP/2.0"; got != want {
542 t.Errorf("body = %q; want %q", got, want)
543 }
544}
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000545
546type capitalizeReader struct {
547 r io.Reader
548}
549
550func (cr capitalizeReader) Read(p []byte) (n int, err error) {
551 n, err = cr.r.Read(p)
552 for i, b := range p[:n] {
553 if b >= 'a' && b <= 'z' {
554 p[i] = b - ('a' - 'A')
555 }
556 }
557 return
558}
559
560type flushWriter struct {
561 w io.Writer
562}
563
564func (fw flushWriter) Write(p []byte) (n int, err error) {
565 n, err = fw.w.Write(p)
566 if f, ok := fw.w.(http.Flusher); ok {
567 f.Flush()
568 }
569 return
570}
571
572type clientTester struct {
573 t *testing.T
574 tr *Transport
575 sc, cc net.Conn // server and client conn
576 fr *Framer // server's framer
577 client func() error
578 server func() error
579}
580
581func newClientTester(t *testing.T) *clientTester {
582 var dialOnce struct {
583 sync.Mutex
584 dialed bool
585 }
586 ct := &clientTester{
587 t: t,
588 }
589 ct.tr = &Transport{
590 TLSClientConfig: tlsConfigInsecure,
591 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
592 dialOnce.Lock()
593 defer dialOnce.Unlock()
594 if dialOnce.dialed {
595 return nil, errors.New("only one dial allowed in test mode")
596 }
597 dialOnce.dialed = true
598 return ct.cc, nil
599 },
600 }
601
602 ln := newLocalListener(t)
603 cc, err := net.Dial("tcp", ln.Addr().String())
604 if err != nil {
605 t.Fatal(err)
606
607 }
608 sc, err := ln.Accept()
609 if err != nil {
610 t.Fatal(err)
611 }
612 ln.Close()
613 ct.cc = cc
614 ct.sc = sc
615 ct.fr = NewFramer(sc, sc)
616 return ct
617}
618
619func newLocalListener(t *testing.T) net.Listener {
620 ln, err := net.Listen("tcp4", "127.0.0.1:0")
621 if err == nil {
622 return ln
623 }
624 ln, err = net.Listen("tcp6", "[::1]:0")
625 if err != nil {
626 t.Fatal(err)
627 }
628 return ln
629}
630
631func (ct *clientTester) greet() {
632 buf := make([]byte, len(ClientPreface))
633 _, err := io.ReadFull(ct.sc, buf)
634 if err != nil {
635 ct.t.Fatalf("reading client preface: %v", err)
636 }
637 f, err := ct.fr.ReadFrame()
638 if err != nil {
639 ct.t.Fatalf("Reading client settings frame: %v", err)
640 }
641 if sf, ok := f.(*SettingsFrame); !ok {
642 ct.t.Fatalf("Wanted client settings frame; got %v", f)
643 _ = sf // stash it away?
644 }
645 if err := ct.fr.WriteSettings(); err != nil {
646 ct.t.Fatal(err)
647 }
648 if err := ct.fr.WriteSettingsAck(); err != nil {
649 ct.t.Fatal(err)
650 }
651}
652
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000653func (ct *clientTester) cleanup() {
654 ct.tr.CloseIdleConnections()
655}
656
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000657func (ct *clientTester) run() {
658 errc := make(chan error, 2)
659 ct.start("client", errc, ct.client)
660 ct.start("server", errc, ct.server)
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000661 defer ct.cleanup()
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000662 for i := 0; i < 2; i++ {
663 if err := <-errc; err != nil {
664 ct.t.Error(err)
665 return
666 }
667 }
668}
669
670func (ct *clientTester) start(which string, errc chan<- error, fn func() error) {
671 go func() {
672 finished := false
673 var err error
674 defer func() {
675 if !finished {
676 err = fmt.Errorf("%s goroutine didn't finish.", which)
677 } else if err != nil {
678 err = fmt.Errorf("%s: %v", which, err)
679 }
680 errc <- err
681 }()
682 err = fn()
683 finished = true
684 }()
685}
686
687type countingReader struct {
688 n *int64
689}
690
691func (r countingReader) Read(p []byte) (n int, err error) {
692 for i := range p {
693 p[i] = byte(i)
694 }
695 atomic.AddInt64(r.n, int64(len(p)))
696 return len(p), err
697}
698
699func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) }
700func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) }
701
702func testTransportReqBodyAfterResponse(t *testing.T, status int) {
703 const bodySize = 10 << 20
704 ct := newClientTester(t)
705 ct.client = func() error {
706 var n int64 // atomic
707 req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize))
708 if err != nil {
709 return err
710 }
711 res, err := ct.tr.RoundTrip(req)
712 if err != nil {
713 return fmt.Errorf("RoundTrip: %v", err)
714 }
715 defer res.Body.Close()
716 if res.StatusCode != status {
717 return fmt.Errorf("status code = %v; want %v", res.StatusCode, status)
718 }
719 slurp, err := ioutil.ReadAll(res.Body)
720 if err != nil {
721 return fmt.Errorf("Slurp: %v", err)
722 }
723 if len(slurp) > 0 {
724 return fmt.Errorf("unexpected body: %q", slurp)
725 }
726 if status == 200 {
727 if got := atomic.LoadInt64(&n); got != bodySize {
728 return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize)
729 }
730 } else {
731 if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize {
732 return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize)
733 }
734 }
735 return nil
736 }
737 ct.server = func() error {
738 ct.greet()
739 var buf bytes.Buffer
740 enc := hpack.NewEncoder(&buf)
741 var dataRecv int64
742 var closed bool
743 for {
744 f, err := ct.fr.ReadFrame()
745 if err != nil {
746 return err
747 }
748 //println(fmt.Sprintf("server got frame: %v", f))
749 switch f := f.(type) {
750 case *WindowUpdateFrame, *SettingsFrame:
751 case *HeadersFrame:
752 if !f.HeadersEnded() {
753 return fmt.Errorf("headers should have END_HEADERS be ended: %v", f)
754 }
755 if f.StreamEnded() {
756 return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f)
757 }
758 time.Sleep(50 * time.Millisecond) // let client send body
759 enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
760 ct.fr.WriteHeaders(HeadersFrameParam{
761 StreamID: f.StreamID,
762 EndHeaders: true,
763 EndStream: false,
764 BlockFragment: buf.Bytes(),
765 })
766 case *DataFrame:
767 dataLen := len(f.Data())
768 dataRecv += int64(dataLen)
769 if dataLen > 0 {
770 if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
771 return err
772 }
773 if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
774 return err
775 }
776 }
777 if !closed && ((status != 200 && dataRecv > 0) ||
778 (status == 200 && dataRecv == bodySize)) {
779 closed = true
780 if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil {
781 return err
782 }
783 return nil
784 }
785 default:
786 return fmt.Errorf("Unexpected client frame %v", f)
787 }
788 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000789 }
790 ct.run()
791}
792
793// See golang.org/issue/13444
794func TestTransportFullDuplex(t *testing.T) {
795 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
796 w.WriteHeader(200) // redundant but for clarity
797 w.(http.Flusher).Flush()
798 io.Copy(flushWriter{w}, capitalizeReader{r.Body})
799 fmt.Fprintf(w, "bye.\n")
800 }, optOnlyServer)
801 defer st.Close()
802
803 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
804 defer tr.CloseIdleConnections()
805 c := &http.Client{Transport: tr}
806
807 pr, pw := io.Pipe()
808 req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr))
809 if err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +0900810 t.Fatal(err)
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000811 }
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800812 req.ContentLength = -1
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000813 res, err := c.Do(req)
814 if err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +0900815 t.Fatal(err)
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000816 }
817 defer res.Body.Close()
818 if res.StatusCode != 200 {
819 t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200)
820 }
821 bs := bufio.NewScanner(res.Body)
822 want := func(v string) {
823 if !bs.Scan() {
824 t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err())
825 }
826 }
827 write := func(v string) {
828 _, err := io.WriteString(pw, v)
829 if err != nil {
830 t.Fatalf("pipe write: %v", err)
831 }
832 }
833 write("foo\n")
834 want("FOO")
835 write("bar\n")
836 want("BAR")
837 pw.Close()
838 want("bye.")
839 if err := bs.Err(); err != nil {
840 t.Fatal(err)
841 }
842}
Brad Fitzpatrick961116a2016-01-05 14:53:21 -0800843
844func TestTransportConnectRequest(t *testing.T) {
845 gotc := make(chan *http.Request, 1)
846 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
847 gotc <- r
848 }, optOnlyServer)
849 defer st.Close()
850
851 u, err := url.Parse(st.ts.URL)
852 if err != nil {
853 t.Fatal(err)
854 }
855
856 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
857 defer tr.CloseIdleConnections()
858 c := &http.Client{Transport: tr}
859
860 tests := []struct {
861 req *http.Request
862 want string
863 }{
864 {
865 req: &http.Request{
866 Method: "CONNECT",
867 Header: http.Header{},
868 URL: u,
869 },
870 want: u.Host,
871 },
872 {
873 req: &http.Request{
874 Method: "CONNECT",
875 Header: http.Header{},
876 URL: u,
877 Host: "example.com:123",
878 },
879 want: "example.com:123",
880 },
881 }
882
883 for i, tt := range tests {
884 res, err := c.Do(tt.req)
885 if err != nil {
886 t.Errorf("%d. RoundTrip = %v", i, err)
887 continue
888 }
889 res.Body.Close()
890 req := <-gotc
891 if req.Method != "CONNECT" {
892 t.Errorf("method = %q; want CONNECT", req.Method)
893 }
894 if req.Host != tt.want {
895 t.Errorf("Host = %q; want %q", req.Host, tt.want)
896 }
897 if req.URL.Host != tt.want {
898 t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
899 }
900 }
901}
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000902
903type headerType int
904
905const (
906 noHeader headerType = iota // omitted
907 oneHeader
908 splitHeader // broken into continuation on purpose
909)
910
911const (
912 f0 = noHeader
913 f1 = oneHeader
914 f2 = splitHeader
915 d0 = false
916 d1 = true
917)
918
919// Test all 36 combinations of response frame orders:
920// (3 ways of 100-continue) * (2 ways of headers) * (2 ways of data) * (3 ways of trailers):func TestTransportResponsePattern_00f0(t *testing.T) { testTransportResponsePattern(h0, h1, false, h0) }
921// Generated by http://play.golang.org/p/SScqYKJYXd
922func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) }
923func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) }
924func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) }
925func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) }
926func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) }
927func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) }
928func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) }
929func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) }
930func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) }
931func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) }
932func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) }
933func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) }
934func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) }
935func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) }
936func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) }
937func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) }
938func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) }
939func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) }
940func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) }
941func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) }
942func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) }
943func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) }
944func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) }
945func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) }
946func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) }
947func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) }
948func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) }
949func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) }
950func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) }
951func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) }
952func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) }
953func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) }
954func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) }
955func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) }
956func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) }
957func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) }
958
959func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
960 const reqBody = "some request body"
961 const resBody = "some response body"
962
963 if resHeader == noHeader {
964 // TODO: test 100-continue followed by immediate
965 // server stream reset, without headers in the middle?
966 panic("invalid combination")
967 }
968
969 ct := newClientTester(t)
970 ct.client = func() error {
971 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody))
972 if expect100Continue != noHeader {
973 req.Header.Set("Expect", "100-continue")
974 }
975 res, err := ct.tr.RoundTrip(req)
976 if err != nil {
977 return fmt.Errorf("RoundTrip: %v", err)
978 }
979 defer res.Body.Close()
980 if res.StatusCode != 200 {
981 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
982 }
983 slurp, err := ioutil.ReadAll(res.Body)
984 if err != nil {
985 return fmt.Errorf("Slurp: %v", err)
986 }
987 wantBody := resBody
988 if !withData {
989 wantBody = ""
990 }
991 if string(slurp) != wantBody {
992 return fmt.Errorf("body = %q; want %q", slurp, wantBody)
993 }
994 if trailers == noHeader {
995 if len(res.Trailer) > 0 {
996 t.Errorf("Trailer = %v; want none", res.Trailer)
997 }
998 } else {
999 want := http.Header{"Some-Trailer": {"some-value"}}
1000 if !reflect.DeepEqual(res.Trailer, want) {
1001 t.Errorf("Trailer = %v; want %v", res.Trailer, want)
1002 }
1003 }
1004 return nil
1005 }
1006 ct.server = func() error {
1007 ct.greet()
1008 var buf bytes.Buffer
1009 enc := hpack.NewEncoder(&buf)
1010
1011 for {
1012 f, err := ct.fr.ReadFrame()
1013 if err != nil {
1014 return err
1015 }
1016 switch f := f.(type) {
1017 case *WindowUpdateFrame, *SettingsFrame:
1018 case *DataFrame:
1019 // ignore for now.
1020 case *HeadersFrame:
1021 endStream := false
1022 send := func(mode headerType) {
1023 hbf := buf.Bytes()
1024 switch mode {
1025 case oneHeader:
1026 ct.fr.WriteHeaders(HeadersFrameParam{
1027 StreamID: f.StreamID,
1028 EndHeaders: true,
1029 EndStream: endStream,
1030 BlockFragment: hbf,
1031 })
1032 case splitHeader:
1033 if len(hbf) < 2 {
1034 panic("too small")
1035 }
1036 ct.fr.WriteHeaders(HeadersFrameParam{
1037 StreamID: f.StreamID,
1038 EndHeaders: false,
1039 EndStream: endStream,
1040 BlockFragment: hbf[:1],
1041 })
1042 ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
1043 default:
1044 panic("bogus mode")
1045 }
1046 }
1047 if expect100Continue != noHeader {
1048 buf.Reset()
1049 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
1050 send(expect100Continue)
1051 }
1052 // Response headers (1+ frames; 1 or 2 in this test, but never 0)
1053 {
1054 buf.Reset()
1055 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1056 enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"})
1057 enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"})
1058 if trailers != noHeader {
1059 enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"})
1060 }
1061 endStream = withData == false && trailers == noHeader
1062 send(resHeader)
1063 }
1064 if withData {
1065 endStream = trailers == noHeader
1066 ct.fr.WriteData(f.StreamID, endStream, []byte(resBody))
1067 }
1068 if trailers != noHeader {
1069 endStream = true
1070 buf.Reset()
1071 enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"})
1072 send(trailers)
1073 }
1074 return nil
1075 }
1076 }
1077 }
1078 ct.run()
1079}
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001080
Blake Mizerany0e6d34e2016-01-09 15:16:57 -08001081func TestTransportReceiveUndeclaredTrailer(t *testing.T) {
1082 ct := newClientTester(t)
1083 ct.client = func() error {
1084 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1085 res, err := ct.tr.RoundTrip(req)
1086 if err != nil {
1087 return fmt.Errorf("RoundTrip: %v", err)
1088 }
1089 defer res.Body.Close()
1090 if res.StatusCode != 200 {
1091 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
1092 }
1093 slurp, err := ioutil.ReadAll(res.Body)
1094 if err != nil {
1095 return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil)
1096 }
1097 if len(slurp) > 0 {
1098 return fmt.Errorf("body = %q; want nothing", slurp)
1099 }
1100 if _, ok := res.Trailer["Some-Trailer"]; !ok {
1101 return fmt.Errorf("expected Some-Trailer")
1102 }
1103 return nil
1104 }
1105 ct.server = func() error {
1106 ct.greet()
1107
1108 var n int
1109 var hf *HeadersFrame
1110 for hf == nil && n < 10 {
1111 f, err := ct.fr.ReadFrame()
1112 if err != nil {
1113 return err
1114 }
1115 hf, _ = f.(*HeadersFrame)
1116 n++
1117 }
1118
1119 var buf bytes.Buffer
1120 enc := hpack.NewEncoder(&buf)
1121
1122 // send headers without Trailer header
1123 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1124 ct.fr.WriteHeaders(HeadersFrameParam{
1125 StreamID: hf.StreamID,
1126 EndHeaders: true,
1127 EndStream: false,
1128 BlockFragment: buf.Bytes(),
1129 })
1130
1131 // send trailers
1132 buf.Reset()
1133 enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"})
1134 ct.fr.WriteHeaders(HeadersFrameParam{
1135 StreamID: hf.StreamID,
1136 EndHeaders: true,
1137 EndStream: true,
1138 BlockFragment: buf.Bytes(),
1139 })
1140 return nil
1141 }
1142 ct.run()
1143}
1144
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001145func TestTransportInvalidTrailer_Pseudo1(t *testing.T) {
1146 testTransportInvalidTrailer_Pseudo(t, oneHeader)
1147}
1148func TestTransportInvalidTrailer_Pseudo2(t *testing.T) {
1149 testTransportInvalidTrailer_Pseudo(t, splitHeader)
1150}
1151func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301152 testInvalidTrailer(t, trailers, pseudoHeaderError(":colon"), func(enc *hpack.Encoder) {
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001153 enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"})
1154 enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
1155 })
1156}
1157
1158func TestTransportInvalidTrailer_Capital1(t *testing.T) {
1159 testTransportInvalidTrailer_Capital(t, oneHeader)
1160}
1161func TestTransportInvalidTrailer_Capital2(t *testing.T) {
1162 testTransportInvalidTrailer_Capital(t, splitHeader)
1163}
1164func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301165 testInvalidTrailer(t, trailers, headerFieldNameError("Capital"), func(enc *hpack.Encoder) {
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001166 enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
1167 enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"})
1168 })
1169}
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001170func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301171 testInvalidTrailer(t, oneHeader, headerFieldNameError(""), func(enc *hpack.Encoder) {
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001172 enc.WriteField(hpack.HeaderField{Name: "", Value: "bad"})
1173 })
1174}
1175func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301176 testInvalidTrailer(t, oneHeader, headerFieldValueError("has\nnewline"), func(enc *hpack.Encoder) {
1177 enc.WriteField(hpack.HeaderField{Name: "x", Value: "has\nnewline"})
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001178 })
1179}
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001180
1181func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) {
1182 ct := newClientTester(t)
1183 ct.client = func() error {
1184 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1185 res, err := ct.tr.RoundTrip(req)
1186 if err != nil {
1187 return fmt.Errorf("RoundTrip: %v", err)
1188 }
1189 defer res.Body.Close()
1190 if res.StatusCode != 200 {
1191 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
1192 }
1193 slurp, err := ioutil.ReadAll(res.Body)
1194 if err != wantErr {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301195 return fmt.Errorf("res.Body ReadAll error = %q, %#v; want %T of %#v", slurp, err, wantErr, wantErr)
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001196 }
1197 if len(slurp) > 0 {
1198 return fmt.Errorf("body = %q; want nothing", slurp)
1199 }
1200 return nil
1201 }
1202 ct.server = func() error {
1203 ct.greet()
1204 var buf bytes.Buffer
1205 enc := hpack.NewEncoder(&buf)
1206
1207 for {
1208 f, err := ct.fr.ReadFrame()
1209 if err != nil {
1210 return err
1211 }
1212 switch f := f.(type) {
1213 case *HeadersFrame:
1214 var endStream bool
1215 send := func(mode headerType) {
1216 hbf := buf.Bytes()
1217 switch mode {
1218 case oneHeader:
1219 ct.fr.WriteHeaders(HeadersFrameParam{
1220 StreamID: f.StreamID,
1221 EndHeaders: true,
1222 EndStream: endStream,
1223 BlockFragment: hbf,
1224 })
1225 case splitHeader:
1226 if len(hbf) < 2 {
1227 panic("too small")
1228 }
1229 ct.fr.WriteHeaders(HeadersFrameParam{
1230 StreamID: f.StreamID,
1231 EndHeaders: false,
1232 EndStream: endStream,
1233 BlockFragment: hbf[:1],
1234 })
1235 ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
1236 default:
1237 panic("bogus mode")
1238 }
1239 }
1240 // Response headers (1+ frames; 1 or 2 in this test, but never 0)
1241 {
1242 buf.Reset()
1243 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1244 enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"})
1245 endStream = false
1246 send(oneHeader)
1247 }
1248 // Trailers:
1249 {
1250 endStream = true
1251 buf.Reset()
1252 writeTrailer(enc)
1253 send(trailers)
1254 }
1255 return nil
1256 }
1257 }
1258 }
1259 ct.run()
1260}
1261
1262func TestTransportChecksResponseHeaderListSize(t *testing.T) {
1263 ct := newClientTester(t)
1264 ct.client = func() error {
1265 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1266 res, err := ct.tr.RoundTrip(req)
1267 if err != errResponseHeaderListSize {
1268 if res != nil {
1269 res.Body.Close()
1270 }
1271 size := int64(0)
1272 for k, vv := range res.Header {
1273 for _, v := range vv {
1274 size += int64(len(k)) + int64(len(v)) + 32
1275 }
1276 }
1277 return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size)
1278 }
1279 return nil
1280 }
1281 ct.server = func() error {
1282 ct.greet()
1283 var buf bytes.Buffer
1284 enc := hpack.NewEncoder(&buf)
1285
1286 for {
1287 f, err := ct.fr.ReadFrame()
1288 if err != nil {
1289 return err
1290 }
1291 switch f := f.(type) {
1292 case *HeadersFrame:
1293 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1294 large := strings.Repeat("a", 1<<10)
1295 for i := 0; i < 5042; i++ {
1296 enc.WriteField(hpack.HeaderField{Name: large, Value: large})
1297 }
1298 if size, want := buf.Len(), 6329; size != want {
1299 // Note: this number might change if
1300 // our hpack implementation
1301 // changes. That's fine. This is
1302 // just a sanity check that our
1303 // response can fit in a single
1304 // header block fragment frame.
1305 return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
1306 }
1307 ct.fr.WriteHeaders(HeadersFrameParam{
1308 StreamID: f.StreamID,
1309 EndHeaders: true,
1310 EndStream: true,
1311 BlockFragment: buf.Bytes(),
1312 })
1313 return nil
1314 }
1315 }
1316 }
1317 ct.run()
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001318}
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001319
1320// Test that the the Transport returns a typed error from Response.Body.Read calls
1321// when the server sends an error. (here we use a panic, since that should generate
1322// a stream error, but others like cancel should be similar)
1323func TestTransportBodyReadErrorType(t *testing.T) {
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001324 doPanic := make(chan bool, 1)
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001325 st := newServerTester(t,
1326 func(w http.ResponseWriter, r *http.Request) {
1327 w.(http.Flusher).Flush() // force headers out
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001328 <-doPanic
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001329 panic("boom")
1330 },
1331 optOnlyServer,
1332 optQuiet,
1333 )
1334 defer st.Close()
1335
1336 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1337 defer tr.CloseIdleConnections()
1338 c := &http.Client{Transport: tr}
1339
1340 res, err := c.Get(st.ts.URL)
1341 if err != nil {
1342 t.Fatal(err)
1343 }
1344 defer res.Body.Close()
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001345 doPanic <- true
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001346 buf := make([]byte, 100)
1347 n, err := res.Body.Read(buf)
1348 want := StreamError{StreamID: 0x1, Code: 0x2}
1349 if !reflect.DeepEqual(want, err) {
1350 t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
1351 }
1352}
Brad Fitzpatrick76365a42016-01-12 19:24:09 +00001353
1354// golang.org/issue/13924
1355// This used to fail after many iterations, especially with -race:
1356// go test -v -run=TestTransportDoubleCloseOnWriteError -count=500 -race
1357func TestTransportDoubleCloseOnWriteError(t *testing.T) {
1358 var (
1359 mu sync.Mutex
1360 conn net.Conn // to close if set
1361 )
1362
1363 st := newServerTester(t,
1364 func(w http.ResponseWriter, r *http.Request) {
1365 mu.Lock()
1366 defer mu.Unlock()
1367 if conn != nil {
1368 conn.Close()
1369 }
1370 },
1371 optOnlyServer,
1372 )
1373 defer st.Close()
1374
1375 tr := &Transport{
1376 TLSClientConfig: tlsConfigInsecure,
1377 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1378 tc, err := tls.Dial(network, addr, cfg)
1379 if err != nil {
1380 return nil, err
1381 }
1382 mu.Lock()
1383 defer mu.Unlock()
1384 conn = tc
1385 return tc, nil
1386 },
1387 }
1388 defer tr.CloseIdleConnections()
1389 c := &http.Client{Transport: tr}
1390 c.Get(st.ts.URL)
1391}
Brad Fitzpatrickf5de73e2016-01-19 03:50:30 +00001392
1393// Test that the http1 Transport.DisableKeepAlives option is respected
1394// and connections are closed as soon as idle.
1395// See golang.org/issue/14008
1396func TestTransportDisableKeepAlives(t *testing.T) {
1397 st := newServerTester(t,
1398 func(w http.ResponseWriter, r *http.Request) {
1399 io.WriteString(w, "hi")
1400 },
1401 optOnlyServer,
1402 )
1403 defer st.Close()
1404
1405 connClosed := make(chan struct{}) // closed on tls.Conn.Close
1406 tr := &Transport{
1407 t1: &http.Transport{
1408 DisableKeepAlives: true,
1409 },
1410 TLSClientConfig: tlsConfigInsecure,
1411 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1412 tc, err := tls.Dial(network, addr, cfg)
1413 if err != nil {
1414 return nil, err
1415 }
1416 return &noteCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil
1417 },
1418 }
1419 c := &http.Client{Transport: tr}
1420 res, err := c.Get(st.ts.URL)
1421 if err != nil {
1422 t.Fatal(err)
1423 }
1424 if _, err := ioutil.ReadAll(res.Body); err != nil {
1425 t.Fatal(err)
1426 }
1427 defer res.Body.Close()
1428
1429 select {
1430 case <-connClosed:
1431 case <-time.After(1 * time.Second):
1432 t.Errorf("timeout")
1433 }
1434
1435}
1436
1437// Test concurrent requests with Transport.DisableKeepAlives. We can share connections,
1438// but when things are totally idle, it still needs to close.
1439func TestTransportDisableKeepAlives_Concurrency(t *testing.T) {
1440 const D = 25 * time.Millisecond
1441 st := newServerTester(t,
1442 func(w http.ResponseWriter, r *http.Request) {
1443 time.Sleep(D)
1444 io.WriteString(w, "hi")
1445 },
1446 optOnlyServer,
1447 )
1448 defer st.Close()
1449
1450 var dials int32
1451 var conns sync.WaitGroup
1452 tr := &Transport{
1453 t1: &http.Transport{
1454 DisableKeepAlives: true,
1455 },
1456 TLSClientConfig: tlsConfigInsecure,
1457 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1458 tc, err := tls.Dial(network, addr, cfg)
1459 if err != nil {
1460 return nil, err
1461 }
1462 atomic.AddInt32(&dials, 1)
1463 conns.Add(1)
1464 return &noteCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil
1465 },
1466 }
1467 c := &http.Client{Transport: tr}
1468 var reqs sync.WaitGroup
1469 const N = 20
1470 for i := 0; i < N; i++ {
1471 reqs.Add(1)
1472 if i == N-1 {
1473 // For the final request, try to make all the
1474 // others close. This isn't verified in the
1475 // count, other than the Log statement, since
1476 // it's so timing dependent. This test is
1477 // really to make sure we don't interrupt a
1478 // valid request.
1479 time.Sleep(D * 2)
1480 }
1481 go func() {
1482 defer reqs.Done()
1483 res, err := c.Get(st.ts.URL)
1484 if err != nil {
1485 t.Error(err)
1486 return
1487 }
1488 if _, err := ioutil.ReadAll(res.Body); err != nil {
1489 t.Error(err)
1490 return
1491 }
1492 res.Body.Close()
1493 }()
1494 }
1495 reqs.Wait()
1496 conns.Wait()
1497 t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N)
1498}
1499
1500type noteCloseConn struct {
1501 net.Conn
1502 onceClose sync.Once
1503 closefn func()
1504}
1505
1506func (c *noteCloseConn) Close() error {
1507 c.onceClose.Do(c.closefn)
1508 return c.Conn.Close()
1509}
1510
1511func isTimeout(err error) bool {
1512 switch err := err.(type) {
1513 case nil:
1514 return false
1515 case *url.Error:
1516 return isTimeout(err.Err)
1517 case net.Error:
1518 return err.Timeout()
1519 }
1520 return false
1521}
1522
1523// Test that the http1 Transport.ResponseHeaderTimeout option and cancel is sent.
1524func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) {
1525 testTransportResponseHeaderTimeout(t, false)
1526}
1527func TestTransportResponseHeaderTimeout_Body(t *testing.T) {
1528 testTransportResponseHeaderTimeout(t, true)
1529}
1530
1531func testTransportResponseHeaderTimeout(t *testing.T, body bool) {
1532 ct := newClientTester(t)
1533 ct.tr.t1 = &http.Transport{
1534 ResponseHeaderTimeout: 5 * time.Millisecond,
1535 }
1536 ct.client = func() error {
1537 c := &http.Client{Transport: ct.tr}
1538 var err error
1539 var n int64
1540 const bodySize = 4 << 20
1541 if body {
1542 _, err = c.Post("https://dummy.tld/", "text/foo", io.LimitReader(countingReader{&n}, bodySize))
1543 } else {
1544 _, err = c.Get("https://dummy.tld/")
1545 }
1546 if !isTimeout(err) {
1547 t.Errorf("client expected timeout error; got %#v", err)
1548 }
1549 if body && n != bodySize {
1550 t.Errorf("only read %d bytes of body; want %d", n, bodySize)
1551 }
1552 return nil
1553 }
1554 ct.server = func() error {
1555 ct.greet()
1556 for {
1557 f, err := ct.fr.ReadFrame()
1558 if err != nil {
1559 t.Logf("ReadFrame: %v", err)
1560 return nil
1561 }
1562 switch f := f.(type) {
1563 case *DataFrame:
1564 dataLen := len(f.Data())
1565 if dataLen > 0 {
1566 if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
1567 return err
1568 }
1569 if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
1570 return err
1571 }
1572 }
1573 case *RSTStreamFrame:
1574 if f.StreamID == 1 && f.ErrCode == ErrCodeCancel {
1575 return nil
1576 }
1577 }
1578 }
Brad Fitzpatrickf5de73e2016-01-19 03:50:30 +00001579 }
1580 ct.run()
1581}
1582
1583func TestTransportDisableCompression(t *testing.T) {
1584 const body = "sup"
1585 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1586 want := http.Header{
1587 "User-Agent": []string{"Go-http-client/2.0"},
1588 }
1589 if !reflect.DeepEqual(r.Header, want) {
1590 t.Errorf("request headers = %v; want %v", r.Header, want)
1591 }
1592 }, optOnlyServer)
1593 defer st.Close()
1594
1595 tr := &Transport{
1596 TLSClientConfig: tlsConfigInsecure,
1597 t1: &http.Transport{
1598 DisableCompression: true,
1599 },
1600 }
1601 defer tr.CloseIdleConnections()
1602
1603 req, err := http.NewRequest("GET", st.ts.URL, nil)
1604 if err != nil {
1605 t.Fatal(err)
1606 }
1607 res, err := tr.RoundTrip(req)
1608 if err != nil {
1609 t.Fatal(err)
1610 }
1611 defer res.Body.Close()
1612}
Brad Fitzpatrick493a2622016-02-04 19:41:12 +00001613
1614// RFC 7540 section 8.1.2.2
1615func TestTransportRejectsConnHeaders(t *testing.T) {
1616 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1617 var got []string
1618 for k := range r.Header {
1619 got = append(got, k)
1620 }
1621 sort.Strings(got)
1622 w.Header().Set("Got-Header", strings.Join(got, ","))
1623 }, optOnlyServer)
1624 defer st.Close()
1625
1626 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1627 defer tr.CloseIdleConnections()
1628
1629 tests := []struct {
1630 key string
1631 value []string
1632 want string
1633 }{
1634 {
1635 key: "Upgrade",
1636 value: []string{"anything"},
1637 want: "ERROR: http2: invalid Upgrade request header",
1638 },
1639 {
1640 key: "Connection",
1641 value: []string{"foo"},
1642 want: "ERROR: http2: invalid Connection request header",
1643 },
1644 {
1645 key: "Connection",
1646 value: []string{"close"},
1647 want: "Accept-Encoding,User-Agent",
1648 },
1649 {
1650 key: "Connection",
1651 value: []string{"close", "something-else"},
1652 want: "ERROR: http2: invalid Connection request header",
1653 },
1654 {
1655 key: "Connection",
1656 value: []string{"keep-alive"},
1657 want: "Accept-Encoding,User-Agent",
1658 },
1659 {
1660 key: "Proxy-Connection", // just deleted and ignored
1661 value: []string{"keep-alive"},
1662 want: "Accept-Encoding,User-Agent",
1663 },
1664 {
1665 key: "Transfer-Encoding",
1666 value: []string{""},
1667 want: "Accept-Encoding,User-Agent",
1668 },
1669 {
1670 key: "Transfer-Encoding",
1671 value: []string{"foo"},
1672 want: "ERROR: http2: invalid Transfer-Encoding request header",
1673 },
1674 {
1675 key: "Transfer-Encoding",
1676 value: []string{"chunked"},
1677 want: "Accept-Encoding,User-Agent",
1678 },
1679 {
1680 key: "Transfer-Encoding",
1681 value: []string{"chunked", "other"},
1682 want: "ERROR: http2: invalid Transfer-Encoding request header",
1683 },
1684 {
1685 key: "Content-Length",
1686 value: []string{"123"},
1687 want: "Accept-Encoding,User-Agent",
1688 },
Roland Shoemaker024ed622016-04-03 12:24:15 -07001689 {
1690 key: "Keep-Alive",
1691 value: []string{"doop"},
1692 want: "Accept-Encoding,User-Agent",
1693 },
Brad Fitzpatrick493a2622016-02-04 19:41:12 +00001694 }
1695
1696 for _, tt := range tests {
1697 req, _ := http.NewRequest("GET", st.ts.URL, nil)
1698 req.Header[tt.key] = tt.value
1699 res, err := tr.RoundTrip(req)
1700 var got string
1701 if err != nil {
1702 got = fmt.Sprintf("ERROR: %v", err)
1703 } else {
1704 got = res.Header.Get("Got-Header")
1705 res.Body.Close()
1706 }
1707 if got != tt.want {
1708 t.Errorf("For key %q, value %q, got = %q; want %q", tt.key, tt.value, got, tt.want)
1709 }
1710 }
1711}
Brad Fitzpatrickcbbbe2b2016-02-13 01:55:36 +00001712
Brad Fitzpatrick5916dcb2016-05-18 23:19:24 +00001713// golang.org/issue/14048
1714func TestTransportFailsOnInvalidHeaders(t *testing.T) {
1715 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1716 var got []string
1717 for k := range r.Header {
1718 got = append(got, k)
1719 }
1720 sort.Strings(got)
1721 w.Header().Set("Got-Header", strings.Join(got, ","))
1722 }, optOnlyServer)
1723 defer st.Close()
1724
1725 tests := [...]struct {
1726 h http.Header
1727 wantErr string
1728 }{
1729 0: {
1730 h: http.Header{"with space": {"foo"}},
1731 wantErr: `invalid HTTP header name "with space"`,
1732 },
1733 1: {
1734 h: http.Header{"name": {"Брэд"}},
1735 wantErr: "", // okay
1736 },
1737 2: {
1738 h: http.Header{"имя": {"Brad"}},
1739 wantErr: `invalid HTTP header name "имя"`,
1740 },
1741 3: {
1742 h: http.Header{"foo": {"foo\x01bar"}},
1743 wantErr: `invalid HTTP header value "foo\x01bar" for header "foo"`,
1744 },
1745 }
1746
1747 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1748 defer tr.CloseIdleConnections()
1749
1750 for i, tt := range tests {
1751 req, _ := http.NewRequest("GET", st.ts.URL, nil)
1752 req.Header = tt.h
1753 res, err := tr.RoundTrip(req)
1754 var bad bool
1755 if tt.wantErr == "" {
1756 if err != nil {
1757 bad = true
1758 t.Errorf("case %d: error = %v; want no error", i, err)
1759 }
1760 } else {
1761 if !strings.Contains(fmt.Sprint(err), tt.wantErr) {
1762 bad = true
1763 t.Errorf("case %d: error = %v; want error %q", i, err, tt.wantErr)
1764 }
1765 }
1766 if err == nil {
1767 if bad {
1768 t.Logf("case %d: server got headers %q", i, res.Header.Get("Got-Header"))
1769 }
1770 res.Body.Close()
1771 }
1772 }
1773}
1774
Brad Fitzpatrickcbbbe2b2016-02-13 01:55:36 +00001775// Tests that gzipReader doesn't crash on a second Read call following
1776// the first Read call's gzip.NewReader returning an error.
1777func TestGzipReader_DoubleReadCrash(t *testing.T) {
1778 gz := &gzipReader{
1779 body: ioutil.NopCloser(strings.NewReader("0123456789")),
1780 }
1781 var buf [1]byte
1782 n, err1 := gz.Read(buf[:])
1783 if n != 0 || !strings.Contains(fmt.Sprint(err1), "invalid header") {
1784 t.Fatalf("Read = %v, %v; want 0, invalid header", n, err1)
1785 }
1786 n, err2 := gz.Read(buf[:])
1787 if n != 0 || err2 != err1 {
1788 t.Fatalf("second Read = %v, %v; want 0, %v", n, err2, err1)
1789 }
1790}
Brad Fitzpatrick3f5b0e62016-02-25 18:11:36 +00001791
1792func TestTransportNewTLSConfig(t *testing.T) {
1793 tests := [...]struct {
1794 conf *tls.Config
1795 host string
1796 want *tls.Config
1797 }{
1798 // Normal case.
1799 0: {
1800 conf: nil,
1801 host: "foo.com",
1802 want: &tls.Config{
1803 ServerName: "foo.com",
1804 NextProtos: []string{NextProtoTLS},
1805 },
1806 },
1807
1808 // User-provided name (bar.com) takes precedence:
1809 1: {
1810 conf: &tls.Config{
1811 ServerName: "bar.com",
1812 },
1813 host: "foo.com",
1814 want: &tls.Config{
1815 ServerName: "bar.com",
1816 NextProtos: []string{NextProtoTLS},
1817 },
1818 },
1819
1820 // NextProto is prepended:
1821 2: {
1822 conf: &tls.Config{
1823 NextProtos: []string{"foo", "bar"},
1824 },
1825 host: "example.com",
1826 want: &tls.Config{
1827 ServerName: "example.com",
1828 NextProtos: []string{NextProtoTLS, "foo", "bar"},
1829 },
1830 },
1831
1832 // NextProto is not duplicated:
1833 3: {
1834 conf: &tls.Config{
1835 NextProtos: []string{"foo", "bar", NextProtoTLS},
1836 },
1837 host: "example.com",
1838 want: &tls.Config{
1839 ServerName: "example.com",
1840 NextProtos: []string{"foo", "bar", NextProtoTLS},
1841 },
1842 },
1843 }
1844 for i, tt := range tests {
1845 tr := &Transport{TLSClientConfig: tt.conf}
1846 got := tr.newTLSConfig(tt.host)
1847 if !reflect.DeepEqual(got, tt.want) {
1848 t.Errorf("%d. got %#v; want %#v", i, got, tt.want)
1849 }
1850 }
1851}
Brad Fitzpatrick991d3e32016-03-24 11:19:19 +11001852
1853// The Google GFE responds to HEAD requests with a HEADERS frame
1854// without END_STREAM, followed by a 0-length DATA frame with
1855// END_STREAM. Make sure we don't get confused by that. (We did.)
1856func TestTransportReadHeadResponse(t *testing.T) {
1857 ct := newClientTester(t)
1858 clientDone := make(chan struct{})
1859 ct.client = func() error {
1860 defer close(clientDone)
1861 req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
1862 res, err := ct.tr.RoundTrip(req)
1863 if err != nil {
1864 return err
1865 }
1866 if res.ContentLength != 123 {
1867 return fmt.Errorf("Content-Length = %d; want 123", res.ContentLength)
1868 }
1869 slurp, err := ioutil.ReadAll(res.Body)
1870 if err != nil {
1871 return fmt.Errorf("ReadAll: %v", err)
1872 }
1873 if len(slurp) > 0 {
1874 return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp)
1875 }
1876 return nil
1877 }
1878 ct.server = func() error {
1879 ct.greet()
1880 for {
1881 f, err := ct.fr.ReadFrame()
1882 if err != nil {
1883 t.Logf("ReadFrame: %v", err)
1884 return nil
1885 }
1886 hf, ok := f.(*HeadersFrame)
1887 if !ok {
1888 continue
1889 }
1890 var buf bytes.Buffer
1891 enc := hpack.NewEncoder(&buf)
1892 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1893 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
1894 ct.fr.WriteHeaders(HeadersFrameParam{
1895 StreamID: hf.StreamID,
1896 EndHeaders: true,
1897 EndStream: false, // as the GFE does
1898 BlockFragment: buf.Bytes(),
1899 })
1900 ct.fr.WriteData(hf.StreamID, true, nil)
1901
1902 <-clientDone
1903 return nil
1904 }
Brad Fitzpatrick991d3e32016-03-24 11:19:19 +11001905 }
1906 ct.run()
1907}
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +00001908
1909type neverEnding byte
1910
1911func (b neverEnding) Read(p []byte) (int, error) {
1912 for i := range p {
1913 p[i] = byte(b)
1914 }
1915 return len(p), nil
1916}
1917
1918// golang.org/issue/15425: test that a handler closing the request
1919// body doesn't terminate the stream to the peer. (It just stops
1920// readability from the handler's side, and eventually the client
1921// runs out of flow control tokens)
1922func TestTransportHandlerBodyClose(t *testing.T) {
1923 const bodySize = 10 << 20
1924 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1925 r.Body.Close()
1926 io.Copy(w, io.LimitReader(neverEnding('A'), bodySize))
1927 }, optOnlyServer)
1928 defer st.Close()
1929
1930 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1931 defer tr.CloseIdleConnections()
1932
1933 g0 := runtime.NumGoroutine()
1934
1935 const numReq = 10
1936 for i := 0; i < numReq; i++ {
1937 req, err := http.NewRequest("POST", st.ts.URL, struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
1938 if err != nil {
1939 t.Fatal(err)
1940 }
1941 res, err := tr.RoundTrip(req)
1942 if err != nil {
1943 t.Fatal(err)
1944 }
1945 n, err := io.Copy(ioutil.Discard, res.Body)
1946 res.Body.Close()
1947 if n != bodySize || err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +09001948 t.Fatalf("req#%d: Copy = %d, %v; want %d, nil", i, n, err, bodySize)
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +00001949 }
1950 }
1951 tr.CloseIdleConnections()
1952
1953 gd := runtime.NumGoroutine() - g0
1954 if gd > numReq/2 {
1955 t.Errorf("appeared to leak goroutines")
1956 }
1957
1958}
Andrew Gerrand154d9f92016-06-06 15:43:46 +10001959
1960// https://golang.org/issue/15930
1961func TestTransportFlowControl(t *testing.T) {
1962 const (
1963 total = 100 << 20 // 100MB
1964 bufLen = 1 << 16
1965 )
1966
1967 var wrote int64 // updated atomically
1968 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1969 b := make([]byte, bufLen)
1970 for wrote < total {
1971 n, err := w.Write(b)
1972 atomic.AddInt64(&wrote, int64(n))
1973 if err != nil {
1974 t.Errorf("ResponseWriter.Write error: %v", err)
1975 break
1976 }
1977 w.(http.Flusher).Flush()
1978 }
1979 }, optOnlyServer)
1980
1981 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1982 defer tr.CloseIdleConnections()
1983 req, err := http.NewRequest("GET", st.ts.URL, nil)
1984 if err != nil {
1985 t.Fatal("NewRequest error:", err)
1986 }
1987 resp, err := tr.RoundTrip(req)
1988 if err != nil {
1989 t.Fatal("RoundTrip error:", err)
1990 }
1991 defer resp.Body.Close()
1992
1993 var read int64
1994 b := make([]byte, bufLen)
1995 for {
1996 n, err := resp.Body.Read(b)
1997 if err == io.EOF {
1998 break
1999 }
2000 if err != nil {
2001 t.Fatal("Read error:", err)
2002 }
2003 read += int64(n)
2004
2005 const max = transportDefaultStreamFlow
2006 if w := atomic.LoadInt64(&wrote); -max > read-w || read-w > max {
2007 t.Fatalf("Too much data inflight: server wrote %v bytes but client only received %v", w, read)
2008 }
2009
2010 // Let the server get ahead of the client.
2011 time.Sleep(1 * time.Millisecond)
2012 }
2013}
Brad Fitzpatrickef2e00e2016-06-28 16:00:16 -07002014
2015// golang.org/issue/14627 -- if the server sends a GOAWAY frame, make
2016// the Transport remember it and return it back to users (via
2017// RoundTrip or request body reads) if needed (e.g. if the server
2018// proceeds to close the TCP connection before the client gets its
2019// response)
2020func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) {
2021 testTransportUsesGoAwayDebugError(t, false)
2022}
2023
2024func TestTransportUsesGoAwayDebugError_Body(t *testing.T) {
2025 testTransportUsesGoAwayDebugError(t, true)
2026}
2027
2028func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) {
2029 ct := newClientTester(t)
2030 clientDone := make(chan struct{})
2031
2032 const goAwayErrCode = ErrCodeHTTP11Required // arbitrary
2033 const goAwayDebugData = "some debug data"
2034
2035 ct.client = func() error {
2036 defer close(clientDone)
2037 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2038 res, err := ct.tr.RoundTrip(req)
2039 if failMidBody {
2040 if err != nil {
2041 return fmt.Errorf("unexpected client RoundTrip error: %v", err)
2042 }
2043 _, err = io.Copy(ioutil.Discard, res.Body)
2044 res.Body.Close()
2045 }
2046 want := GoAwayError{
2047 LastStreamID: 0,
2048 ErrCode: goAwayErrCode,
2049 DebugData: goAwayDebugData,
2050 }
2051 if !reflect.DeepEqual(err, want) {
2052 t.Errorf("RoundTrip error = %T: %#v, want %T (%#T)", err, err, want, want)
2053 }
2054 return nil
2055 }
2056 ct.server = func() error {
2057 ct.greet()
2058 for {
2059 f, err := ct.fr.ReadFrame()
2060 if err != nil {
2061 t.Logf("ReadFrame: %v", err)
2062 return nil
2063 }
2064 hf, ok := f.(*HeadersFrame)
2065 if !ok {
2066 continue
2067 }
2068 if failMidBody {
2069 var buf bytes.Buffer
2070 enc := hpack.NewEncoder(&buf)
2071 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2072 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
2073 ct.fr.WriteHeaders(HeadersFrameParam{
2074 StreamID: hf.StreamID,
2075 EndHeaders: true,
2076 EndStream: false,
2077 BlockFragment: buf.Bytes(),
2078 })
2079 }
2080 ct.fr.WriteGoAway(0, goAwayErrCode, []byte(goAwayDebugData))
2081 ct.sc.Close()
2082 <-clientDone
2083 return nil
2084 }
2085 }
2086 ct.run()
2087}