blob: a7cce9474b4ee7b234a6fb9a0e1f73e08aa0ca29 [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)
Brad Fitzpatricka7282882016-07-07 15:24:52 -0700153 }, optOnlyServer, func(c net.Conn, st http.ConnState) {
154 t.Logf("conn %v is now state %v", c.RemoteAddr(), st)
155 })
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800156 defer st.Close()
Blake Mizeranye1a58162015-10-24 16:42:11 -0700157 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800158 defer tr.CloseIdleConnections()
159 get := func() string {
160 req, err := http.NewRequest("GET", st.ts.URL, nil)
161 if err != nil {
162 t.Fatal(err)
163 }
Brad Fitzpatrick493a2622016-02-04 19:41:12 +0000164 modReq(req)
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800165 res, err := tr.RoundTrip(req)
166 if err != nil {
167 t.Fatal(err)
168 }
169 defer res.Body.Close()
170 slurp, err := ioutil.ReadAll(res.Body)
171 if err != nil {
172 t.Fatalf("Body read: %v", err)
173 }
174 addr := strings.TrimSpace(string(slurp))
175 if addr == "" {
176 t.Fatalf("didn't get an addr in response")
177 }
178 return addr
179 }
180 first := get()
181 second := get()
Brad Fitzpatrick493a2622016-02-04 19:41:12 +0000182 return first == second
183}
184
185func TestTransportReusesConns(t *testing.T) {
186 if !onSameConn(t, func(*http.Request) {}) {
187 t.Errorf("first and second responses were on different connections")
188 }
189}
190
191func TestTransportReusesConn_RequestClose(t *testing.T) {
192 if onSameConn(t, func(r *http.Request) { r.Close = true }) {
193 t.Errorf("first and second responses were not on different connections")
194 }
195}
196
197func TestTransportReusesConn_ConnClose(t *testing.T) {
198 if onSameConn(t, func(r *http.Request) { r.Header.Set("Connection", "close") }) {
199 t.Errorf("first and second responses were not on different connections")
Brad Fitzpatrick45702ea2015-02-08 21:57:59 -0800200 }
201}
Blake Mizerany35769072015-02-08 22:09:17 -0800202
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000203// Tests that the Transport only keeps one pending dial open per destination address.
204// https://golang.org/issue/13397
205func TestTransportGroupsPendingDials(t *testing.T) {
206 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
207 io.WriteString(w, r.RemoteAddr)
208 }, optOnlyServer)
209 defer st.Close()
210 tr := &Transport{
211 TLSClientConfig: tlsConfigInsecure,
212 }
213 defer tr.CloseIdleConnections()
214 var (
215 mu sync.Mutex
216 dials = map[string]int{}
217 )
218 var wg sync.WaitGroup
219 for i := 0; i < 10; i++ {
220 wg.Add(1)
221 go func() {
222 defer wg.Done()
223 req, err := http.NewRequest("GET", st.ts.URL, nil)
224 if err != nil {
225 t.Error(err)
226 return
227 }
228 res, err := tr.RoundTrip(req)
229 if err != nil {
230 t.Error(err)
231 return
232 }
233 defer res.Body.Close()
234 slurp, err := ioutil.ReadAll(res.Body)
235 if err != nil {
236 t.Errorf("Body read: %v", err)
237 }
238 addr := strings.TrimSpace(string(slurp))
239 if addr == "" {
240 t.Errorf("didn't get an addr in response")
241 }
242 mu.Lock()
243 dials[addr]++
244 mu.Unlock()
245 }()
246 }
247 wg.Wait()
248 if len(dials) != 1 {
249 t.Errorf("saw %d dials; want 1: %v", len(dials), dials)
250 }
251 tr.CloseIdleConnections()
252 if err := retry(50, 10*time.Millisecond, func() error {
253 cp, ok := tr.connPool().(*clientConnPool)
254 if !ok {
255 return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool())
256 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000257 cp.mu.Lock()
258 defer cp.mu.Unlock()
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000259 if len(cp.dialing) != 0 {
260 return fmt.Errorf("dialing map = %v; want empty", cp.dialing)
261 }
262 if len(cp.conns) != 0 {
263 return fmt.Errorf("conns = %v; want empty", cp.conns)
264 }
265 if len(cp.keys) != 0 {
266 return fmt.Errorf("keys = %v; want empty", cp.keys)
267 }
268 return nil
269 }); err != nil {
Mikio Hara1d7a0b22016-01-07 09:41:45 +0900270 t.Errorf("State of pool after CloseIdleConnections: %v", err)
Brad Fitzpatrick195180c2015-11-30 18:41:58 +0000271 }
272}
273
274func retry(tries int, delay time.Duration, fn func() error) error {
275 var err error
276 for i := 0; i < tries; i++ {
277 err = fn()
278 if err == nil {
279 return nil
280 }
281 time.Sleep(delay)
282 }
283 return err
284}
285
Blake Mizerany35769072015-02-08 22:09:17 -0800286func TestTransportAbortClosesPipes(t *testing.T) {
287 shutdown := make(chan struct{})
288 st := newServerTester(t,
289 func(w http.ResponseWriter, r *http.Request) {
290 w.(http.Flusher).Flush()
291 <-shutdown
292 },
293 optOnlyServer,
294 )
295 defer st.Close()
296 defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
297
298 done := make(chan struct{})
299 requestMade := make(chan struct{})
300 go func() {
301 defer close(done)
Blake Mizeranye1a58162015-10-24 16:42:11 -0700302 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
Blake Mizerany35769072015-02-08 22:09:17 -0800303 req, err := http.NewRequest("GET", st.ts.URL, nil)
304 if err != nil {
305 t.Fatal(err)
306 }
307 res, err := tr.RoundTrip(req)
308 if err != nil {
309 t.Fatal(err)
310 }
311 defer res.Body.Close()
312 close(requestMade)
313 _, err = ioutil.ReadAll(res.Body)
314 if err == nil {
315 t.Error("expected error from res.Body.Read")
316 }
317 }()
318
319 <-requestMade
320 // Now force the serve loop to end, via closing the connection.
321 st.closeConn()
322 // deadlock? that's a bug.
323 select {
324 case <-done:
325 case <-time.After(3 * time.Second):
326 t.Fatal("timeout")
327 }
328}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500329
Blake Mizeranyce84af22015-10-27 23:17:12 -0700330// TODO: merge this with TestTransportBody to make TestTransportRequest? This
331// could be a table-driven test with extra goodies.
332func TestTransportPath(t *testing.T) {
333 gotc := make(chan *url.URL, 1)
334 st := newServerTester(t,
335 func(w http.ResponseWriter, r *http.Request) {
336 gotc <- r.URL
337 },
338 optOnlyServer,
339 )
340 defer st.Close()
341
342 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
343 defer tr.CloseIdleConnections()
344 const (
345 path = "/testpath"
346 query = "q=1"
347 )
348 surl := st.ts.URL + path + "?" + query
349 req, err := http.NewRequest("POST", surl, nil)
350 if err != nil {
351 t.Fatal(err)
352 }
353 c := &http.Client{Transport: tr}
354 res, err := c.Do(req)
355 if err != nil {
356 t.Fatal(err)
357 }
358 defer res.Body.Close()
359 got := <-gotc
360 if got.Path != path {
361 t.Errorf("Read Path = %q; want %q", got.Path, path)
362 }
363 if got.RawQuery != query {
364 t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
365 }
366}
367
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000368func randString(n int) string {
369 rnd := rand.New(rand.NewSource(int64(n)))
370 b := make([]byte, n)
371 for i := range b {
372 b[i] = byte(rnd.Intn(256))
373 }
374 return string(b)
375}
376
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500377func TestTransportBody(t *testing.T) {
Brad Fitzpatrick4d06dbd2016-03-21 23:17:53 +0000378 bodyTests := []struct {
379 body string
380 noContentLen bool
381 }{
382 {body: "some message"},
383 {body: "some message", noContentLen: true},
384 {body: ""},
385 {body: "", noContentLen: true},
386 {body: strings.Repeat("a", 1<<20), noContentLen: true},
387 {body: strings.Repeat("a", 1<<20)},
388 {body: randString(16<<10 - 1)},
389 {body: randString(16 << 10)},
390 {body: randString(16<<10 + 1)},
391 {body: randString(512<<10 - 1)},
392 {body: randString(512 << 10)},
393 {body: randString(512<<10 + 1)},
394 {body: randString(1<<20 - 1)},
395 {body: randString(1 << 20)},
396 {body: randString(1<<20 + 2)},
397 }
398
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800399 type reqInfo struct {
400 req *http.Request
401 slurp []byte
402 err error
403 }
404 gotc := make(chan reqInfo, 1)
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500405 st := newServerTester(t,
406 func(w http.ResponseWriter, r *http.Request) {
407 slurp, err := ioutil.ReadAll(r.Body)
408 if err != nil {
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800409 gotc <- reqInfo{err: err}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500410 } else {
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800411 gotc <- reqInfo{req: r, slurp: slurp}
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500412 }
413 },
414 optOnlyServer,
415 )
416 defer st.Close()
417
Blake Mizerany1b277612015-10-27 22:40:40 -0700418 for i, tt := range bodyTests {
419 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
420 defer tr.CloseIdleConnections()
421
422 var body io.Reader = strings.NewReader(tt.body)
423 if tt.noContentLen {
424 body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
425 }
426 req, err := http.NewRequest("POST", st.ts.URL, body)
427 if err != nil {
428 t.Fatalf("#%d: %v", i, err)
429 }
430 c := &http.Client{Transport: tr}
431 res, err := c.Do(req)
432 if err != nil {
433 t.Fatalf("#%d: %v", i, err)
434 }
435 defer res.Body.Close()
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800436 ri := <-gotc
437 if ri.err != nil {
Mikio Hara7f882712016-02-05 10:48:01 +0900438 t.Errorf("#%d: read error: %v", i, ri.err)
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800439 continue
440 }
441 if got := string(ri.slurp); got != tt.body {
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000442 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 -0700443 }
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800444 wantLen := int64(len(tt.body))
445 if tt.noContentLen && tt.body != "" {
446 wantLen = -1
447 }
448 if ri.req.ContentLength != wantLen {
449 t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen)
450 }
Brad Fitzpatrick09d2a412015-10-21 15:37:53 -0500451 }
452}
Blake Mizeranye1a58162015-10-24 16:42:11 -0700453
Brad Fitzpatrick2fd7f152015-10-29 17:44:04 +0000454func shortString(v string) string {
455 const maxLen = 100
456 if len(v) <= maxLen {
457 return v
458 }
459 return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
460}
461
Blake Mizeranye1a58162015-10-24 16:42:11 -0700462func TestTransportDialTLS(t *testing.T) {
463 var mu sync.Mutex // guards following
464 var gotReq, didDial bool
465
466 ts := newServerTester(t,
467 func(w http.ResponseWriter, r *http.Request) {
468 mu.Lock()
469 gotReq = true
470 mu.Unlock()
471 },
472 optOnlyServer,
473 )
474 defer ts.Close()
475 tr := &Transport{
476 DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
477 mu.Lock()
478 didDial = true
479 mu.Unlock()
480 cfg.InsecureSkipVerify = true
481 c, err := tls.Dial(netw, addr, cfg)
482 if err != nil {
483 return nil, err
484 }
485 return c, c.Handshake()
486 },
487 }
488 defer tr.CloseIdleConnections()
489 client := &http.Client{Transport: tr}
490 res, err := client.Get(ts.ts.URL)
491 if err != nil {
492 t.Fatal(err)
493 }
494 res.Body.Close()
495 mu.Lock()
496 if !gotReq {
497 t.Error("didn't get request")
498 }
499 if !didDial {
500 t.Error("didn't use dial hook")
501 }
502}
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100503
504func TestConfigureTransport(t *testing.T) {
505 t1 := &http.Transport{}
506 err := ConfigureTransport(t1)
507 if err == errTransportVersion {
508 t.Skip(err)
509 }
510 if err != nil {
511 t.Fatal(err)
512 }
513 if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) {
514 // Laziness, to avoid buildtags.
515 t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got)
516 }
Brad Fitzpatrickb304fd02015-12-14 17:57:33 +0000517 wantNextProtos := []string{"h2", "http/1.1"}
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100518 if t1.TLSClientConfig == nil {
519 t.Errorf("nil t1.TLSClientConfig")
Brad Fitzpatrickb304fd02015-12-14 17:57:33 +0000520 } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) {
521 t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos)
Brad Fitzpatrick042ba422015-11-08 11:16:06 +0100522 }
523 if err := ConfigureTransport(t1); err == nil {
524 t.Error("unexpected success on second call to ConfigureTransport")
525 }
526
527 // And does it work?
528 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
529 io.WriteString(w, r.Proto)
530 }, optOnlyServer)
531 defer st.Close()
532
533 t1.TLSClientConfig.InsecureSkipVerify = true
534 c := &http.Client{Transport: t1}
535 res, err := c.Get(st.ts.URL)
536 if err != nil {
537 t.Fatal(err)
538 }
539 slurp, err := ioutil.ReadAll(res.Body)
540 if err != nil {
541 t.Fatal(err)
542 }
543 if got, want := string(slurp), "HTTP/2.0"; got != want {
544 t.Errorf("body = %q; want %q", got, want)
545 }
546}
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000547
548type capitalizeReader struct {
549 r io.Reader
550}
551
552func (cr capitalizeReader) Read(p []byte) (n int, err error) {
553 n, err = cr.r.Read(p)
554 for i, b := range p[:n] {
555 if b >= 'a' && b <= 'z' {
556 p[i] = b - ('a' - 'A')
557 }
558 }
559 return
560}
561
562type flushWriter struct {
563 w io.Writer
564}
565
566func (fw flushWriter) Write(p []byte) (n int, err error) {
567 n, err = fw.w.Write(p)
568 if f, ok := fw.w.(http.Flusher); ok {
569 f.Flush()
570 }
571 return
572}
573
574type clientTester struct {
575 t *testing.T
576 tr *Transport
577 sc, cc net.Conn // server and client conn
578 fr *Framer // server's framer
579 client func() error
580 server func() error
581}
582
583func newClientTester(t *testing.T) *clientTester {
584 var dialOnce struct {
585 sync.Mutex
586 dialed bool
587 }
588 ct := &clientTester{
589 t: t,
590 }
591 ct.tr = &Transport{
592 TLSClientConfig: tlsConfigInsecure,
593 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
594 dialOnce.Lock()
595 defer dialOnce.Unlock()
596 if dialOnce.dialed {
597 return nil, errors.New("only one dial allowed in test mode")
598 }
599 dialOnce.dialed = true
600 return ct.cc, nil
601 },
602 }
603
604 ln := newLocalListener(t)
605 cc, err := net.Dial("tcp", ln.Addr().String())
606 if err != nil {
607 t.Fatal(err)
608
609 }
610 sc, err := ln.Accept()
611 if err != nil {
612 t.Fatal(err)
613 }
614 ln.Close()
615 ct.cc = cc
616 ct.sc = sc
617 ct.fr = NewFramer(sc, sc)
618 return ct
619}
620
621func newLocalListener(t *testing.T) net.Listener {
622 ln, err := net.Listen("tcp4", "127.0.0.1:0")
623 if err == nil {
624 return ln
625 }
626 ln, err = net.Listen("tcp6", "[::1]:0")
627 if err != nil {
628 t.Fatal(err)
629 }
630 return ln
631}
632
633func (ct *clientTester) greet() {
634 buf := make([]byte, len(ClientPreface))
635 _, err := io.ReadFull(ct.sc, buf)
636 if err != nil {
637 ct.t.Fatalf("reading client preface: %v", err)
638 }
639 f, err := ct.fr.ReadFrame()
640 if err != nil {
641 ct.t.Fatalf("Reading client settings frame: %v", err)
642 }
643 if sf, ok := f.(*SettingsFrame); !ok {
644 ct.t.Fatalf("Wanted client settings frame; got %v", f)
645 _ = sf // stash it away?
646 }
647 if err := ct.fr.WriteSettings(); err != nil {
648 ct.t.Fatal(err)
649 }
650 if err := ct.fr.WriteSettingsAck(); err != nil {
651 ct.t.Fatal(err)
652 }
653}
654
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -0700655func (ct *clientTester) readNonSettingsFrame() (Frame, error) {
656 for {
657 f, err := ct.fr.ReadFrame()
658 if err != nil {
659 return nil, err
660 }
661 if _, ok := f.(*SettingsFrame); ok {
662 continue
663 }
664 return f, nil
665 }
666}
667
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000668func (ct *clientTester) cleanup() {
669 ct.tr.CloseIdleConnections()
670}
671
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000672func (ct *clientTester) run() {
673 errc := make(chan error, 2)
674 ct.start("client", errc, ct.client)
675 ct.start("server", errc, ct.server)
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000676 defer ct.cleanup()
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000677 for i := 0; i < 2; i++ {
678 if err := <-errc; err != nil {
679 ct.t.Error(err)
680 return
681 }
682 }
683}
684
685func (ct *clientTester) start(which string, errc chan<- error, fn func() error) {
686 go func() {
687 finished := false
688 var err error
689 defer func() {
690 if !finished {
691 err = fmt.Errorf("%s goroutine didn't finish.", which)
692 } else if err != nil {
693 err = fmt.Errorf("%s: %v", which, err)
694 }
695 errc <- err
696 }()
697 err = fn()
698 finished = true
699 }()
700}
701
Brad Fitzpatricke2ba55e2016-08-02 15:44:32 +0000702func (ct *clientTester) readFrame() (Frame, error) {
703 return readFrameTimeout(ct.fr, 2*time.Second)
704}
705
706func (ct *clientTester) firstHeaders() (*HeadersFrame, error) {
707 for {
708 f, err := ct.readFrame()
709 if err != nil {
710 return nil, fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
711 }
712 switch f.(type) {
713 case *WindowUpdateFrame, *SettingsFrame:
714 continue
715 }
716 hf, ok := f.(*HeadersFrame)
717 if !ok {
718 return nil, fmt.Errorf("Got %T; want HeadersFrame", f)
719 }
720 return hf, nil
721 }
722}
723
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000724type countingReader struct {
725 n *int64
726}
727
728func (r countingReader) Read(p []byte) (n int, err error) {
729 for i := range p {
730 p[i] = byte(i)
731 }
732 atomic.AddInt64(r.n, int64(len(p)))
733 return len(p), err
734}
735
736func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) }
737func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) }
738
739func testTransportReqBodyAfterResponse(t *testing.T, status int) {
740 const bodySize = 10 << 20
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -0700741 clientDone := make(chan struct{})
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000742 ct := newClientTester(t)
743 ct.client = func() error {
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -0700744 defer ct.cc.(*net.TCPConn).CloseWrite()
745 defer close(clientDone)
746
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000747 var n int64 // atomic
748 req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize))
749 if err != nil {
750 return err
751 }
752 res, err := ct.tr.RoundTrip(req)
753 if err != nil {
754 return fmt.Errorf("RoundTrip: %v", err)
755 }
756 defer res.Body.Close()
757 if res.StatusCode != status {
758 return fmt.Errorf("status code = %v; want %v", res.StatusCode, status)
759 }
760 slurp, err := ioutil.ReadAll(res.Body)
761 if err != nil {
762 return fmt.Errorf("Slurp: %v", err)
763 }
764 if len(slurp) > 0 {
765 return fmt.Errorf("unexpected body: %q", slurp)
766 }
767 if status == 200 {
768 if got := atomic.LoadInt64(&n); got != bodySize {
769 return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize)
770 }
771 } else {
772 if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize {
773 return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize)
774 }
775 }
776 return nil
777 }
778 ct.server = func() error {
779 ct.greet()
780 var buf bytes.Buffer
781 enc := hpack.NewEncoder(&buf)
782 var dataRecv int64
783 var closed bool
784 for {
785 f, err := ct.fr.ReadFrame()
786 if err != nil {
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -0700787 select {
788 case <-clientDone:
789 // If the client's done, it
790 // will have reported any
791 // errors on its side.
792 return nil
793 default:
794 return err
795 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000796 }
797 //println(fmt.Sprintf("server got frame: %v", f))
798 switch f := f.(type) {
799 case *WindowUpdateFrame, *SettingsFrame:
800 case *HeadersFrame:
801 if !f.HeadersEnded() {
802 return fmt.Errorf("headers should have END_HEADERS be ended: %v", f)
803 }
804 if f.StreamEnded() {
805 return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f)
806 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000807 case *DataFrame:
808 dataLen := len(f.Data())
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000809 if dataLen > 0 {
Brad Fitzpatrickc9a3c542016-07-13 11:36:29 -0600810 if dataRecv == 0 {
811 enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
812 ct.fr.WriteHeaders(HeadersFrameParam{
813 StreamID: f.StreamID,
814 EndHeaders: true,
815 EndStream: false,
816 BlockFragment: buf.Bytes(),
817 })
818 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000819 if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
820 return err
821 }
822 if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
823 return err
824 }
825 }
Brad Fitzpatrickc9a3c542016-07-13 11:36:29 -0600826 dataRecv += int64(dataLen)
827
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000828 if !closed && ((status != 200 && dataRecv > 0) ||
829 (status == 200 && dataRecv == bodySize)) {
830 closed = true
831 if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil {
832 return err
833 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000834 }
835 default:
836 return fmt.Errorf("Unexpected client frame %v", f)
837 }
838 }
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000839 }
840 ct.run()
841}
842
843// See golang.org/issue/13444
844func TestTransportFullDuplex(t *testing.T) {
845 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
846 w.WriteHeader(200) // redundant but for clarity
847 w.(http.Flusher).Flush()
848 io.Copy(flushWriter{w}, capitalizeReader{r.Body})
849 fmt.Fprintf(w, "bye.\n")
850 }, optOnlyServer)
851 defer st.Close()
852
853 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
854 defer tr.CloseIdleConnections()
855 c := &http.Client{Transport: tr}
856
857 pr, pw := io.Pipe()
858 req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr))
859 if err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +0900860 t.Fatal(err)
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000861 }
Brad Fitzpatrick5c0dae82016-01-18 14:52:20 -0800862 req.ContentLength = -1
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000863 res, err := c.Do(req)
864 if err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +0900865 t.Fatal(err)
Brad Fitzpatrick438097d2015-12-01 22:16:42 +0000866 }
867 defer res.Body.Close()
868 if res.StatusCode != 200 {
869 t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200)
870 }
871 bs := bufio.NewScanner(res.Body)
872 want := func(v string) {
873 if !bs.Scan() {
874 t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err())
875 }
876 }
877 write := func(v string) {
878 _, err := io.WriteString(pw, v)
879 if err != nil {
880 t.Fatalf("pipe write: %v", err)
881 }
882 }
883 write("foo\n")
884 want("FOO")
885 write("bar\n")
886 want("BAR")
887 pw.Close()
888 want("bye.")
889 if err := bs.Err(); err != nil {
890 t.Fatal(err)
891 }
892}
Brad Fitzpatrick961116a2016-01-05 14:53:21 -0800893
894func TestTransportConnectRequest(t *testing.T) {
895 gotc := make(chan *http.Request, 1)
896 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
897 gotc <- r
898 }, optOnlyServer)
899 defer st.Close()
900
901 u, err := url.Parse(st.ts.URL)
902 if err != nil {
903 t.Fatal(err)
904 }
905
906 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
907 defer tr.CloseIdleConnections()
908 c := &http.Client{Transport: tr}
909
910 tests := []struct {
911 req *http.Request
912 want string
913 }{
914 {
915 req: &http.Request{
916 Method: "CONNECT",
917 Header: http.Header{},
918 URL: u,
919 },
920 want: u.Host,
921 },
922 {
923 req: &http.Request{
924 Method: "CONNECT",
925 Header: http.Header{},
926 URL: u,
927 Host: "example.com:123",
928 },
929 want: "example.com:123",
930 },
931 }
932
933 for i, tt := range tests {
934 res, err := c.Do(tt.req)
935 if err != nil {
936 t.Errorf("%d. RoundTrip = %v", i, err)
937 continue
938 }
939 res.Body.Close()
940 req := <-gotc
941 if req.Method != "CONNECT" {
942 t.Errorf("method = %q; want CONNECT", req.Method)
943 }
944 if req.Host != tt.want {
945 t.Errorf("Host = %q; want %q", req.Host, tt.want)
946 }
947 if req.URL.Host != tt.want {
948 t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
949 }
950 }
951}
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +0000952
953type headerType int
954
955const (
956 noHeader headerType = iota // omitted
957 oneHeader
958 splitHeader // broken into continuation on purpose
959)
960
961const (
962 f0 = noHeader
963 f1 = oneHeader
964 f2 = splitHeader
965 d0 = false
966 d1 = true
967)
968
969// Test all 36 combinations of response frame orders:
970// (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) }
971// Generated by http://play.golang.org/p/SScqYKJYXd
972func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) }
973func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) }
974func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) }
975func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) }
976func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) }
977func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) }
978func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) }
979func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) }
980func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) }
981func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) }
982func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) }
983func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) }
984func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) }
985func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) }
986func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) }
987func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) }
988func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) }
989func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) }
990func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) }
991func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) }
992func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) }
993func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) }
994func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) }
995func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) }
996func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) }
997func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) }
998func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) }
999func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) }
1000func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) }
1001func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) }
1002func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) }
1003func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) }
1004func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) }
1005func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) }
1006func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) }
1007func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) }
1008
1009func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
1010 const reqBody = "some request body"
1011 const resBody = "some response body"
1012
1013 if resHeader == noHeader {
1014 // TODO: test 100-continue followed by immediate
1015 // server stream reset, without headers in the middle?
1016 panic("invalid combination")
1017 }
1018
1019 ct := newClientTester(t)
1020 ct.client = func() error {
1021 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody))
1022 if expect100Continue != noHeader {
1023 req.Header.Set("Expect", "100-continue")
1024 }
1025 res, err := ct.tr.RoundTrip(req)
1026 if err != nil {
1027 return fmt.Errorf("RoundTrip: %v", err)
1028 }
1029 defer res.Body.Close()
1030 if res.StatusCode != 200 {
1031 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
1032 }
1033 slurp, err := ioutil.ReadAll(res.Body)
1034 if err != nil {
1035 return fmt.Errorf("Slurp: %v", err)
1036 }
1037 wantBody := resBody
1038 if !withData {
1039 wantBody = ""
1040 }
1041 if string(slurp) != wantBody {
1042 return fmt.Errorf("body = %q; want %q", slurp, wantBody)
1043 }
1044 if trailers == noHeader {
1045 if len(res.Trailer) > 0 {
1046 t.Errorf("Trailer = %v; want none", res.Trailer)
1047 }
1048 } else {
1049 want := http.Header{"Some-Trailer": {"some-value"}}
1050 if !reflect.DeepEqual(res.Trailer, want) {
1051 t.Errorf("Trailer = %v; want %v", res.Trailer, want)
1052 }
1053 }
1054 return nil
1055 }
1056 ct.server = func() error {
1057 ct.greet()
1058 var buf bytes.Buffer
1059 enc := hpack.NewEncoder(&buf)
1060
1061 for {
1062 f, err := ct.fr.ReadFrame()
1063 if err != nil {
1064 return err
1065 }
Brad Fitzpatricke90d6d02016-07-15 16:59:30 +00001066 endStream := false
1067 send := func(mode headerType) {
1068 hbf := buf.Bytes()
1069 switch mode {
1070 case oneHeader:
1071 ct.fr.WriteHeaders(HeadersFrameParam{
1072 StreamID: f.Header().StreamID,
1073 EndHeaders: true,
1074 EndStream: endStream,
1075 BlockFragment: hbf,
1076 })
1077 case splitHeader:
1078 if len(hbf) < 2 {
1079 panic("too small")
1080 }
1081 ct.fr.WriteHeaders(HeadersFrameParam{
1082 StreamID: f.Header().StreamID,
1083 EndHeaders: false,
1084 EndStream: endStream,
1085 BlockFragment: hbf[:1],
1086 })
1087 ct.fr.WriteContinuation(f.Header().StreamID, true, hbf[1:])
1088 default:
1089 panic("bogus mode")
1090 }
1091 }
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +00001092 switch f := f.(type) {
1093 case *WindowUpdateFrame, *SettingsFrame:
1094 case *DataFrame:
Brad Fitzpatricke90d6d02016-07-15 16:59:30 +00001095 if !f.StreamEnded() {
1096 // No need to send flow control tokens. The test request body is tiny.
1097 continue
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +00001098 }
1099 // Response headers (1+ frames; 1 or 2 in this test, but never 0)
1100 {
1101 buf.Reset()
1102 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1103 enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"})
1104 enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"})
1105 if trailers != noHeader {
1106 enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"})
1107 }
1108 endStream = withData == false && trailers == noHeader
1109 send(resHeader)
1110 }
1111 if withData {
1112 endStream = trailers == noHeader
1113 ct.fr.WriteData(f.StreamID, endStream, []byte(resBody))
1114 }
1115 if trailers != noHeader {
1116 endStream = true
1117 buf.Reset()
1118 enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"})
1119 send(trailers)
1120 }
Brad Fitzpatricke90d6d02016-07-15 16:59:30 +00001121 if endStream {
1122 return nil
1123 }
1124 case *HeadersFrame:
1125 if expect100Continue != noHeader {
1126 buf.Reset()
1127 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
1128 send(expect100Continue)
1129 }
Brad Fitzpatrick520af5d2016-01-07 02:53:08 +00001130 }
1131 }
1132 }
1133 ct.run()
1134}
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001135
Blake Mizerany0e6d34e2016-01-09 15:16:57 -08001136func TestTransportReceiveUndeclaredTrailer(t *testing.T) {
1137 ct := newClientTester(t)
1138 ct.client = func() error {
1139 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1140 res, err := ct.tr.RoundTrip(req)
1141 if err != nil {
1142 return fmt.Errorf("RoundTrip: %v", err)
1143 }
1144 defer res.Body.Close()
1145 if res.StatusCode != 200 {
1146 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
1147 }
1148 slurp, err := ioutil.ReadAll(res.Body)
1149 if err != nil {
1150 return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil)
1151 }
1152 if len(slurp) > 0 {
1153 return fmt.Errorf("body = %q; want nothing", slurp)
1154 }
1155 if _, ok := res.Trailer["Some-Trailer"]; !ok {
1156 return fmt.Errorf("expected Some-Trailer")
1157 }
1158 return nil
1159 }
1160 ct.server = func() error {
1161 ct.greet()
1162
1163 var n int
1164 var hf *HeadersFrame
1165 for hf == nil && n < 10 {
1166 f, err := ct.fr.ReadFrame()
1167 if err != nil {
1168 return err
1169 }
1170 hf, _ = f.(*HeadersFrame)
1171 n++
1172 }
1173
1174 var buf bytes.Buffer
1175 enc := hpack.NewEncoder(&buf)
1176
1177 // send headers without Trailer header
1178 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1179 ct.fr.WriteHeaders(HeadersFrameParam{
1180 StreamID: hf.StreamID,
1181 EndHeaders: true,
1182 EndStream: false,
1183 BlockFragment: buf.Bytes(),
1184 })
1185
1186 // send trailers
1187 buf.Reset()
1188 enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"})
1189 ct.fr.WriteHeaders(HeadersFrameParam{
1190 StreamID: hf.StreamID,
1191 EndHeaders: true,
1192 EndStream: true,
1193 BlockFragment: buf.Bytes(),
1194 })
1195 return nil
1196 }
1197 ct.run()
1198}
1199
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001200func TestTransportInvalidTrailer_Pseudo1(t *testing.T) {
1201 testTransportInvalidTrailer_Pseudo(t, oneHeader)
1202}
1203func TestTransportInvalidTrailer_Pseudo2(t *testing.T) {
1204 testTransportInvalidTrailer_Pseudo(t, splitHeader)
1205}
1206func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301207 testInvalidTrailer(t, trailers, pseudoHeaderError(":colon"), func(enc *hpack.Encoder) {
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001208 enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"})
1209 enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
1210 })
1211}
1212
1213func TestTransportInvalidTrailer_Capital1(t *testing.T) {
1214 testTransportInvalidTrailer_Capital(t, oneHeader)
1215}
1216func TestTransportInvalidTrailer_Capital2(t *testing.T) {
1217 testTransportInvalidTrailer_Capital(t, splitHeader)
1218}
1219func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301220 testInvalidTrailer(t, trailers, headerFieldNameError("Capital"), func(enc *hpack.Encoder) {
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001221 enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
1222 enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"})
1223 })
1224}
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001225func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301226 testInvalidTrailer(t, oneHeader, headerFieldNameError(""), func(enc *hpack.Encoder) {
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001227 enc.WriteField(hpack.HeaderField{Name: "", Value: "bad"})
1228 })
1229}
1230func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) {
Brad Fitzpatrick9e1fb3c2016-02-20 14:24:27 +05301231 testInvalidTrailer(t, oneHeader, headerFieldValueError("has\nnewline"), func(enc *hpack.Encoder) {
1232 enc.WriteField(hpack.HeaderField{Name: "x", Value: "has\nnewline"})
Brad Fitzpatrickb2ed34f2016-01-20 20:16:54 +00001233 })
1234}
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001235
1236func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) {
1237 ct := newClientTester(t)
1238 ct.client = func() error {
1239 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1240 res, err := ct.tr.RoundTrip(req)
1241 if err != nil {
1242 return fmt.Errorf("RoundTrip: %v", err)
1243 }
1244 defer res.Body.Close()
1245 if res.StatusCode != 200 {
1246 return fmt.Errorf("status code = %v; want 200", res.StatusCode)
1247 }
1248 slurp, err := ioutil.ReadAll(res.Body)
Brad Fitzpatricke2ba55e2016-08-02 15:44:32 +00001249 se, ok := err.(StreamError)
1250 if !ok || se.Cause != wantErr {
1251 return fmt.Errorf("res.Body ReadAll error = %q, %#v; want StreamError with cause %T, %#v", slurp, err, wantErr, wantErr)
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001252 }
1253 if len(slurp) > 0 {
1254 return fmt.Errorf("body = %q; want nothing", slurp)
1255 }
1256 return nil
1257 }
1258 ct.server = func() error {
1259 ct.greet()
1260 var buf bytes.Buffer
1261 enc := hpack.NewEncoder(&buf)
1262
1263 for {
1264 f, err := ct.fr.ReadFrame()
1265 if err != nil {
1266 return err
1267 }
1268 switch f := f.(type) {
1269 case *HeadersFrame:
1270 var endStream bool
1271 send := func(mode headerType) {
1272 hbf := buf.Bytes()
1273 switch mode {
1274 case oneHeader:
1275 ct.fr.WriteHeaders(HeadersFrameParam{
1276 StreamID: f.StreamID,
1277 EndHeaders: true,
1278 EndStream: endStream,
1279 BlockFragment: hbf,
1280 })
1281 case splitHeader:
1282 if len(hbf) < 2 {
1283 panic("too small")
1284 }
1285 ct.fr.WriteHeaders(HeadersFrameParam{
1286 StreamID: f.StreamID,
1287 EndHeaders: false,
1288 EndStream: endStream,
1289 BlockFragment: hbf[:1],
1290 })
1291 ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
1292 default:
1293 panic("bogus mode")
1294 }
1295 }
1296 // Response headers (1+ frames; 1 or 2 in this test, but never 0)
1297 {
1298 buf.Reset()
1299 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1300 enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"})
1301 endStream = false
1302 send(oneHeader)
1303 }
1304 // Trailers:
1305 {
1306 endStream = true
1307 buf.Reset()
1308 writeTrailer(enc)
1309 send(trailers)
1310 }
1311 return nil
1312 }
1313 }
1314 }
1315 ct.run()
1316}
1317
1318func TestTransportChecksResponseHeaderListSize(t *testing.T) {
1319 ct := newClientTester(t)
1320 ct.client = func() error {
1321 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1322 res, err := ct.tr.RoundTrip(req)
1323 if err != errResponseHeaderListSize {
1324 if res != nil {
1325 res.Body.Close()
1326 }
1327 size := int64(0)
1328 for k, vv := range res.Header {
1329 for _, v := range vv {
1330 size += int64(len(k)) + int64(len(v)) + 32
1331 }
1332 }
1333 return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size)
1334 }
1335 return nil
1336 }
1337 ct.server = func() error {
1338 ct.greet()
1339 var buf bytes.Buffer
1340 enc := hpack.NewEncoder(&buf)
1341
1342 for {
1343 f, err := ct.fr.ReadFrame()
1344 if err != nil {
1345 return err
1346 }
1347 switch f := f.(type) {
1348 case *HeadersFrame:
1349 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1350 large := strings.Repeat("a", 1<<10)
1351 for i := 0; i < 5042; i++ {
1352 enc.WriteField(hpack.HeaderField{Name: large, Value: large})
1353 }
1354 if size, want := buf.Len(), 6329; size != want {
1355 // Note: this number might change if
1356 // our hpack implementation
1357 // changes. That's fine. This is
1358 // just a sanity check that our
1359 // response can fit in a single
1360 // header block fragment frame.
1361 return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
1362 }
1363 ct.fr.WriteHeaders(HeadersFrameParam{
1364 StreamID: f.StreamID,
1365 EndHeaders: true,
1366 EndStream: true,
1367 BlockFragment: buf.Bytes(),
1368 })
1369 return nil
1370 }
1371 }
1372 }
1373 ct.run()
Brad Fitzpatrickf530c4e2016-01-07 08:16:00 -08001374}
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001375
1376// Test that the the Transport returns a typed error from Response.Body.Read calls
1377// when the server sends an error. (here we use a panic, since that should generate
1378// a stream error, but others like cancel should be similar)
1379func TestTransportBodyReadErrorType(t *testing.T) {
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001380 doPanic := make(chan bool, 1)
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001381 st := newServerTester(t,
1382 func(w http.ResponseWriter, r *http.Request) {
1383 w.(http.Flusher).Flush() // force headers out
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001384 <-doPanic
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001385 panic("boom")
1386 },
1387 optOnlyServer,
1388 optQuiet,
1389 )
1390 defer st.Close()
1391
1392 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1393 defer tr.CloseIdleConnections()
1394 c := &http.Client{Transport: tr}
1395
1396 res, err := c.Get(st.ts.URL)
1397 if err != nil {
1398 t.Fatal(err)
1399 }
1400 defer res.Body.Close()
Brad Fitzpatrick341cd082016-01-13 21:09:49 +00001401 doPanic <- true
Brad Fitzpatrick5df54832016-01-11 16:40:14 +00001402 buf := make([]byte, 100)
1403 n, err := res.Body.Read(buf)
1404 want := StreamError{StreamID: 0x1, Code: 0x2}
1405 if !reflect.DeepEqual(want, err) {
1406 t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
1407 }
1408}
Brad Fitzpatrick76365a42016-01-12 19:24:09 +00001409
1410// golang.org/issue/13924
1411// This used to fail after many iterations, especially with -race:
1412// go test -v -run=TestTransportDoubleCloseOnWriteError -count=500 -race
1413func TestTransportDoubleCloseOnWriteError(t *testing.T) {
1414 var (
1415 mu sync.Mutex
1416 conn net.Conn // to close if set
1417 )
1418
1419 st := newServerTester(t,
1420 func(w http.ResponseWriter, r *http.Request) {
1421 mu.Lock()
1422 defer mu.Unlock()
1423 if conn != nil {
1424 conn.Close()
1425 }
1426 },
1427 optOnlyServer,
1428 )
1429 defer st.Close()
1430
1431 tr := &Transport{
1432 TLSClientConfig: tlsConfigInsecure,
1433 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1434 tc, err := tls.Dial(network, addr, cfg)
1435 if err != nil {
1436 return nil, err
1437 }
1438 mu.Lock()
1439 defer mu.Unlock()
1440 conn = tc
1441 return tc, nil
1442 },
1443 }
1444 defer tr.CloseIdleConnections()
1445 c := &http.Client{Transport: tr}
1446 c.Get(st.ts.URL)
1447}
Brad Fitzpatrickf5de73e2016-01-19 03:50:30 +00001448
1449// Test that the http1 Transport.DisableKeepAlives option is respected
1450// and connections are closed as soon as idle.
1451// See golang.org/issue/14008
1452func TestTransportDisableKeepAlives(t *testing.T) {
1453 st := newServerTester(t,
1454 func(w http.ResponseWriter, r *http.Request) {
1455 io.WriteString(w, "hi")
1456 },
1457 optOnlyServer,
1458 )
1459 defer st.Close()
1460
1461 connClosed := make(chan struct{}) // closed on tls.Conn.Close
1462 tr := &Transport{
1463 t1: &http.Transport{
1464 DisableKeepAlives: true,
1465 },
1466 TLSClientConfig: tlsConfigInsecure,
1467 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1468 tc, err := tls.Dial(network, addr, cfg)
1469 if err != nil {
1470 return nil, err
1471 }
1472 return &noteCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil
1473 },
1474 }
1475 c := &http.Client{Transport: tr}
1476 res, err := c.Get(st.ts.URL)
1477 if err != nil {
1478 t.Fatal(err)
1479 }
1480 if _, err := ioutil.ReadAll(res.Body); err != nil {
1481 t.Fatal(err)
1482 }
1483 defer res.Body.Close()
1484
1485 select {
1486 case <-connClosed:
1487 case <-time.After(1 * time.Second):
1488 t.Errorf("timeout")
1489 }
1490
1491}
1492
1493// Test concurrent requests with Transport.DisableKeepAlives. We can share connections,
1494// but when things are totally idle, it still needs to close.
1495func TestTransportDisableKeepAlives_Concurrency(t *testing.T) {
1496 const D = 25 * time.Millisecond
1497 st := newServerTester(t,
1498 func(w http.ResponseWriter, r *http.Request) {
1499 time.Sleep(D)
1500 io.WriteString(w, "hi")
1501 },
1502 optOnlyServer,
1503 )
1504 defer st.Close()
1505
1506 var dials int32
1507 var conns sync.WaitGroup
1508 tr := &Transport{
1509 t1: &http.Transport{
1510 DisableKeepAlives: true,
1511 },
1512 TLSClientConfig: tlsConfigInsecure,
1513 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
1514 tc, err := tls.Dial(network, addr, cfg)
1515 if err != nil {
1516 return nil, err
1517 }
1518 atomic.AddInt32(&dials, 1)
1519 conns.Add(1)
1520 return &noteCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil
1521 },
1522 }
1523 c := &http.Client{Transport: tr}
1524 var reqs sync.WaitGroup
1525 const N = 20
1526 for i := 0; i < N; i++ {
1527 reqs.Add(1)
1528 if i == N-1 {
1529 // For the final request, try to make all the
1530 // others close. This isn't verified in the
1531 // count, other than the Log statement, since
1532 // it's so timing dependent. This test is
1533 // really to make sure we don't interrupt a
1534 // valid request.
1535 time.Sleep(D * 2)
1536 }
1537 go func() {
1538 defer reqs.Done()
1539 res, err := c.Get(st.ts.URL)
1540 if err != nil {
1541 t.Error(err)
1542 return
1543 }
1544 if _, err := ioutil.ReadAll(res.Body); err != nil {
1545 t.Error(err)
1546 return
1547 }
1548 res.Body.Close()
1549 }()
1550 }
1551 reqs.Wait()
1552 conns.Wait()
1553 t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N)
1554}
1555
1556type noteCloseConn struct {
1557 net.Conn
1558 onceClose sync.Once
1559 closefn func()
1560}
1561
1562func (c *noteCloseConn) Close() error {
1563 c.onceClose.Do(c.closefn)
1564 return c.Conn.Close()
1565}
1566
1567func isTimeout(err error) bool {
1568 switch err := err.(type) {
1569 case nil:
1570 return false
1571 case *url.Error:
1572 return isTimeout(err.Err)
1573 case net.Error:
1574 return err.Timeout()
1575 }
1576 return false
1577}
1578
1579// Test that the http1 Transport.ResponseHeaderTimeout option and cancel is sent.
1580func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) {
1581 testTransportResponseHeaderTimeout(t, false)
1582}
1583func TestTransportResponseHeaderTimeout_Body(t *testing.T) {
1584 testTransportResponseHeaderTimeout(t, true)
1585}
1586
1587func testTransportResponseHeaderTimeout(t *testing.T, body bool) {
1588 ct := newClientTester(t)
1589 ct.tr.t1 = &http.Transport{
1590 ResponseHeaderTimeout: 5 * time.Millisecond,
1591 }
1592 ct.client = func() error {
1593 c := &http.Client{Transport: ct.tr}
1594 var err error
1595 var n int64
1596 const bodySize = 4 << 20
1597 if body {
1598 _, err = c.Post("https://dummy.tld/", "text/foo", io.LimitReader(countingReader{&n}, bodySize))
1599 } else {
1600 _, err = c.Get("https://dummy.tld/")
1601 }
1602 if !isTimeout(err) {
1603 t.Errorf("client expected timeout error; got %#v", err)
1604 }
1605 if body && n != bodySize {
1606 t.Errorf("only read %d bytes of body; want %d", n, bodySize)
1607 }
1608 return nil
1609 }
1610 ct.server = func() error {
1611 ct.greet()
1612 for {
1613 f, err := ct.fr.ReadFrame()
1614 if err != nil {
1615 t.Logf("ReadFrame: %v", err)
1616 return nil
1617 }
1618 switch f := f.(type) {
1619 case *DataFrame:
1620 dataLen := len(f.Data())
1621 if dataLen > 0 {
1622 if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
1623 return err
1624 }
1625 if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
1626 return err
1627 }
1628 }
1629 case *RSTStreamFrame:
1630 if f.StreamID == 1 && f.ErrCode == ErrCodeCancel {
1631 return nil
1632 }
1633 }
1634 }
Brad Fitzpatrickf5de73e2016-01-19 03:50:30 +00001635 }
1636 ct.run()
1637}
1638
1639func TestTransportDisableCompression(t *testing.T) {
1640 const body = "sup"
1641 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1642 want := http.Header{
1643 "User-Agent": []string{"Go-http-client/2.0"},
1644 }
1645 if !reflect.DeepEqual(r.Header, want) {
1646 t.Errorf("request headers = %v; want %v", r.Header, want)
1647 }
1648 }, optOnlyServer)
1649 defer st.Close()
1650
1651 tr := &Transport{
1652 TLSClientConfig: tlsConfigInsecure,
1653 t1: &http.Transport{
1654 DisableCompression: true,
1655 },
1656 }
1657 defer tr.CloseIdleConnections()
1658
1659 req, err := http.NewRequest("GET", st.ts.URL, nil)
1660 if err != nil {
1661 t.Fatal(err)
1662 }
1663 res, err := tr.RoundTrip(req)
1664 if err != nil {
1665 t.Fatal(err)
1666 }
1667 defer res.Body.Close()
1668}
Brad Fitzpatrick493a2622016-02-04 19:41:12 +00001669
1670// RFC 7540 section 8.1.2.2
1671func TestTransportRejectsConnHeaders(t *testing.T) {
1672 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1673 var got []string
1674 for k := range r.Header {
1675 got = append(got, k)
1676 }
1677 sort.Strings(got)
1678 w.Header().Set("Got-Header", strings.Join(got, ","))
1679 }, optOnlyServer)
1680 defer st.Close()
1681
1682 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1683 defer tr.CloseIdleConnections()
1684
1685 tests := []struct {
1686 key string
1687 value []string
1688 want string
1689 }{
1690 {
1691 key: "Upgrade",
1692 value: []string{"anything"},
1693 want: "ERROR: http2: invalid Upgrade request header",
1694 },
1695 {
1696 key: "Connection",
1697 value: []string{"foo"},
1698 want: "ERROR: http2: invalid Connection request header",
1699 },
1700 {
1701 key: "Connection",
1702 value: []string{"close"},
1703 want: "Accept-Encoding,User-Agent",
1704 },
1705 {
1706 key: "Connection",
1707 value: []string{"close", "something-else"},
1708 want: "ERROR: http2: invalid Connection request header",
1709 },
1710 {
1711 key: "Connection",
1712 value: []string{"keep-alive"},
1713 want: "Accept-Encoding,User-Agent",
1714 },
1715 {
1716 key: "Proxy-Connection", // just deleted and ignored
1717 value: []string{"keep-alive"},
1718 want: "Accept-Encoding,User-Agent",
1719 },
1720 {
1721 key: "Transfer-Encoding",
1722 value: []string{""},
1723 want: "Accept-Encoding,User-Agent",
1724 },
1725 {
1726 key: "Transfer-Encoding",
1727 value: []string{"foo"},
1728 want: "ERROR: http2: invalid Transfer-Encoding request header",
1729 },
1730 {
1731 key: "Transfer-Encoding",
1732 value: []string{"chunked"},
1733 want: "Accept-Encoding,User-Agent",
1734 },
1735 {
1736 key: "Transfer-Encoding",
1737 value: []string{"chunked", "other"},
1738 want: "ERROR: http2: invalid Transfer-Encoding request header",
1739 },
1740 {
1741 key: "Content-Length",
1742 value: []string{"123"},
1743 want: "Accept-Encoding,User-Agent",
1744 },
Roland Shoemaker024ed622016-04-03 12:24:15 -07001745 {
1746 key: "Keep-Alive",
1747 value: []string{"doop"},
1748 want: "Accept-Encoding,User-Agent",
1749 },
Brad Fitzpatrick493a2622016-02-04 19:41:12 +00001750 }
1751
1752 for _, tt := range tests {
1753 req, _ := http.NewRequest("GET", st.ts.URL, nil)
1754 req.Header[tt.key] = tt.value
1755 res, err := tr.RoundTrip(req)
1756 var got string
1757 if err != nil {
1758 got = fmt.Sprintf("ERROR: %v", err)
1759 } else {
1760 got = res.Header.Get("Got-Header")
1761 res.Body.Close()
1762 }
1763 if got != tt.want {
1764 t.Errorf("For key %q, value %q, got = %q; want %q", tt.key, tt.value, got, tt.want)
1765 }
1766 }
1767}
Brad Fitzpatrickcbbbe2b2016-02-13 01:55:36 +00001768
Brad Fitzpatrick5916dcb2016-05-18 23:19:24 +00001769// golang.org/issue/14048
1770func TestTransportFailsOnInvalidHeaders(t *testing.T) {
1771 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1772 var got []string
1773 for k := range r.Header {
1774 got = append(got, k)
1775 }
1776 sort.Strings(got)
1777 w.Header().Set("Got-Header", strings.Join(got, ","))
1778 }, optOnlyServer)
1779 defer st.Close()
1780
1781 tests := [...]struct {
1782 h http.Header
1783 wantErr string
1784 }{
1785 0: {
1786 h: http.Header{"with space": {"foo"}},
1787 wantErr: `invalid HTTP header name "with space"`,
1788 },
1789 1: {
1790 h: http.Header{"name": {"Брэд"}},
1791 wantErr: "", // okay
1792 },
1793 2: {
1794 h: http.Header{"имя": {"Brad"}},
1795 wantErr: `invalid HTTP header name "имя"`,
1796 },
1797 3: {
1798 h: http.Header{"foo": {"foo\x01bar"}},
1799 wantErr: `invalid HTTP header value "foo\x01bar" for header "foo"`,
1800 },
1801 }
1802
1803 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1804 defer tr.CloseIdleConnections()
1805
1806 for i, tt := range tests {
1807 req, _ := http.NewRequest("GET", st.ts.URL, nil)
1808 req.Header = tt.h
1809 res, err := tr.RoundTrip(req)
1810 var bad bool
1811 if tt.wantErr == "" {
1812 if err != nil {
1813 bad = true
1814 t.Errorf("case %d: error = %v; want no error", i, err)
1815 }
1816 } else {
1817 if !strings.Contains(fmt.Sprint(err), tt.wantErr) {
1818 bad = true
1819 t.Errorf("case %d: error = %v; want error %q", i, err, tt.wantErr)
1820 }
1821 }
1822 if err == nil {
1823 if bad {
1824 t.Logf("case %d: server got headers %q", i, res.Header.Get("Got-Header"))
1825 }
1826 res.Body.Close()
1827 }
1828 }
1829}
1830
Brad Fitzpatrickcbbbe2b2016-02-13 01:55:36 +00001831// Tests that gzipReader doesn't crash on a second Read call following
1832// the first Read call's gzip.NewReader returning an error.
1833func TestGzipReader_DoubleReadCrash(t *testing.T) {
1834 gz := &gzipReader{
1835 body: ioutil.NopCloser(strings.NewReader("0123456789")),
1836 }
1837 var buf [1]byte
1838 n, err1 := gz.Read(buf[:])
1839 if n != 0 || !strings.Contains(fmt.Sprint(err1), "invalid header") {
1840 t.Fatalf("Read = %v, %v; want 0, invalid header", n, err1)
1841 }
1842 n, err2 := gz.Read(buf[:])
1843 if n != 0 || err2 != err1 {
1844 t.Fatalf("second Read = %v, %v; want 0, %v", n, err2, err1)
1845 }
1846}
Brad Fitzpatrick3f5b0e62016-02-25 18:11:36 +00001847
1848func TestTransportNewTLSConfig(t *testing.T) {
1849 tests := [...]struct {
1850 conf *tls.Config
1851 host string
1852 want *tls.Config
1853 }{
1854 // Normal case.
1855 0: {
1856 conf: nil,
1857 host: "foo.com",
1858 want: &tls.Config{
1859 ServerName: "foo.com",
1860 NextProtos: []string{NextProtoTLS},
1861 },
1862 },
1863
1864 // User-provided name (bar.com) takes precedence:
1865 1: {
1866 conf: &tls.Config{
1867 ServerName: "bar.com",
1868 },
1869 host: "foo.com",
1870 want: &tls.Config{
1871 ServerName: "bar.com",
1872 NextProtos: []string{NextProtoTLS},
1873 },
1874 },
1875
1876 // NextProto is prepended:
1877 2: {
1878 conf: &tls.Config{
1879 NextProtos: []string{"foo", "bar"},
1880 },
1881 host: "example.com",
1882 want: &tls.Config{
1883 ServerName: "example.com",
1884 NextProtos: []string{NextProtoTLS, "foo", "bar"},
1885 },
1886 },
1887
1888 // NextProto is not duplicated:
1889 3: {
1890 conf: &tls.Config{
1891 NextProtos: []string{"foo", "bar", NextProtoTLS},
1892 },
1893 host: "example.com",
1894 want: &tls.Config{
1895 ServerName: "example.com",
1896 NextProtos: []string{"foo", "bar", NextProtoTLS},
1897 },
1898 },
1899 }
1900 for i, tt := range tests {
1901 tr := &Transport{TLSClientConfig: tt.conf}
1902 got := tr.newTLSConfig(tt.host)
1903 if !reflect.DeepEqual(got, tt.want) {
1904 t.Errorf("%d. got %#v; want %#v", i, got, tt.want)
1905 }
1906 }
1907}
Brad Fitzpatrick991d3e32016-03-24 11:19:19 +11001908
1909// The Google GFE responds to HEAD requests with a HEADERS frame
1910// without END_STREAM, followed by a 0-length DATA frame with
1911// END_STREAM. Make sure we don't get confused by that. (We did.)
1912func TestTransportReadHeadResponse(t *testing.T) {
1913 ct := newClientTester(t)
1914 clientDone := make(chan struct{})
1915 ct.client = func() error {
1916 defer close(clientDone)
1917 req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
1918 res, err := ct.tr.RoundTrip(req)
1919 if err != nil {
1920 return err
1921 }
1922 if res.ContentLength != 123 {
1923 return fmt.Errorf("Content-Length = %d; want 123", res.ContentLength)
1924 }
1925 slurp, err := ioutil.ReadAll(res.Body)
1926 if err != nil {
1927 return fmt.Errorf("ReadAll: %v", err)
1928 }
1929 if len(slurp) > 0 {
1930 return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp)
1931 }
1932 return nil
1933 }
1934 ct.server = func() error {
1935 ct.greet()
1936 for {
1937 f, err := ct.fr.ReadFrame()
1938 if err != nil {
1939 t.Logf("ReadFrame: %v", err)
1940 return nil
1941 }
1942 hf, ok := f.(*HeadersFrame)
1943 if !ok {
1944 continue
1945 }
1946 var buf bytes.Buffer
1947 enc := hpack.NewEncoder(&buf)
1948 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
1949 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
1950 ct.fr.WriteHeaders(HeadersFrameParam{
1951 StreamID: hf.StreamID,
1952 EndHeaders: true,
1953 EndStream: false, // as the GFE does
1954 BlockFragment: buf.Bytes(),
1955 })
1956 ct.fr.WriteData(hf.StreamID, true, nil)
1957
1958 <-clientDone
1959 return nil
1960 }
Brad Fitzpatrick991d3e32016-03-24 11:19:19 +11001961 }
1962 ct.run()
1963}
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +00001964
1965type neverEnding byte
1966
1967func (b neverEnding) Read(p []byte) (int, error) {
1968 for i := range p {
1969 p[i] = byte(b)
1970 }
1971 return len(p), nil
1972}
1973
1974// golang.org/issue/15425: test that a handler closing the request
1975// body doesn't terminate the stream to the peer. (It just stops
1976// readability from the handler's side, and eventually the client
1977// runs out of flow control tokens)
1978func TestTransportHandlerBodyClose(t *testing.T) {
1979 const bodySize = 10 << 20
1980 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1981 r.Body.Close()
1982 io.Copy(w, io.LimitReader(neverEnding('A'), bodySize))
1983 }, optOnlyServer)
1984 defer st.Close()
1985
1986 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
1987 defer tr.CloseIdleConnections()
1988
1989 g0 := runtime.NumGoroutine()
1990
1991 const numReq = 10
1992 for i := 0; i < numReq; i++ {
1993 req, err := http.NewRequest("POST", st.ts.URL, struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
1994 if err != nil {
1995 t.Fatal(err)
1996 }
1997 res, err := tr.RoundTrip(req)
1998 if err != nil {
1999 t.Fatal(err)
2000 }
2001 n, err := io.Copy(ioutil.Discard, res.Body)
2002 res.Body.Close()
2003 if n != bodySize || err != nil {
Mikio Haradfd9ed62016-05-26 10:07:17 +09002004 t.Fatalf("req#%d: Copy = %d, %v; want %d, nil", i, n, err, bodySize)
Brad Fitzpatrick4d07e8a2016-05-20 18:55:47 +00002005 }
2006 }
2007 tr.CloseIdleConnections()
2008
2009 gd := runtime.NumGoroutine() - g0
2010 if gd > numReq/2 {
2011 t.Errorf("appeared to leak goroutines")
2012 }
2013
2014}
Andrew Gerrand154d9f92016-06-06 15:43:46 +10002015
2016// https://golang.org/issue/15930
2017func TestTransportFlowControl(t *testing.T) {
2018 const (
2019 total = 100 << 20 // 100MB
2020 bufLen = 1 << 16
2021 )
2022
2023 var wrote int64 // updated atomically
2024 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
2025 b := make([]byte, bufLen)
2026 for wrote < total {
2027 n, err := w.Write(b)
2028 atomic.AddInt64(&wrote, int64(n))
2029 if err != nil {
2030 t.Errorf("ResponseWriter.Write error: %v", err)
2031 break
2032 }
2033 w.(http.Flusher).Flush()
2034 }
2035 }, optOnlyServer)
2036
2037 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
2038 defer tr.CloseIdleConnections()
2039 req, err := http.NewRequest("GET", st.ts.URL, nil)
2040 if err != nil {
2041 t.Fatal("NewRequest error:", err)
2042 }
2043 resp, err := tr.RoundTrip(req)
2044 if err != nil {
2045 t.Fatal("RoundTrip error:", err)
2046 }
2047 defer resp.Body.Close()
2048
2049 var read int64
2050 b := make([]byte, bufLen)
2051 for {
2052 n, err := resp.Body.Read(b)
2053 if err == io.EOF {
2054 break
2055 }
2056 if err != nil {
2057 t.Fatal("Read error:", err)
2058 }
2059 read += int64(n)
2060
2061 const max = transportDefaultStreamFlow
2062 if w := atomic.LoadInt64(&wrote); -max > read-w || read-w > max {
2063 t.Fatalf("Too much data inflight: server wrote %v bytes but client only received %v", w, read)
2064 }
2065
2066 // Let the server get ahead of the client.
2067 time.Sleep(1 * time.Millisecond)
2068 }
2069}
Brad Fitzpatrickef2e00e2016-06-28 16:00:16 -07002070
2071// golang.org/issue/14627 -- if the server sends a GOAWAY frame, make
2072// the Transport remember it and return it back to users (via
2073// RoundTrip or request body reads) if needed (e.g. if the server
2074// proceeds to close the TCP connection before the client gets its
2075// response)
2076func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) {
2077 testTransportUsesGoAwayDebugError(t, false)
2078}
2079
2080func TestTransportUsesGoAwayDebugError_Body(t *testing.T) {
2081 testTransportUsesGoAwayDebugError(t, true)
2082}
2083
2084func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) {
2085 ct := newClientTester(t)
2086 clientDone := make(chan struct{})
2087
2088 const goAwayErrCode = ErrCodeHTTP11Required // arbitrary
2089 const goAwayDebugData = "some debug data"
2090
2091 ct.client = func() error {
2092 defer close(clientDone)
2093 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2094 res, err := ct.tr.RoundTrip(req)
2095 if failMidBody {
2096 if err != nil {
2097 return fmt.Errorf("unexpected client RoundTrip error: %v", err)
2098 }
2099 _, err = io.Copy(ioutil.Discard, res.Body)
2100 res.Body.Close()
2101 }
2102 want := GoAwayError{
Brad Fitzpatrick8e573f42016-06-29 11:55:36 -07002103 LastStreamID: 5,
Brad Fitzpatrickef2e00e2016-06-28 16:00:16 -07002104 ErrCode: goAwayErrCode,
2105 DebugData: goAwayDebugData,
2106 }
2107 if !reflect.DeepEqual(err, want) {
2108 t.Errorf("RoundTrip error = %T: %#v, want %T (%#T)", err, err, want, want)
2109 }
2110 return nil
2111 }
2112 ct.server = func() error {
2113 ct.greet()
2114 for {
2115 f, err := ct.fr.ReadFrame()
2116 if err != nil {
2117 t.Logf("ReadFrame: %v", err)
2118 return nil
2119 }
2120 hf, ok := f.(*HeadersFrame)
2121 if !ok {
2122 continue
2123 }
2124 if failMidBody {
2125 var buf bytes.Buffer
2126 enc := hpack.NewEncoder(&buf)
2127 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2128 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
2129 ct.fr.WriteHeaders(HeadersFrameParam{
2130 StreamID: hf.StreamID,
2131 EndHeaders: true,
2132 EndStream: false,
2133 BlockFragment: buf.Bytes(),
2134 })
2135 }
Brad Fitzpatrick8e573f42016-06-29 11:55:36 -07002136 // Write two GOAWAY frames, to test that the Transport takes
2137 // the interesting parts of both.
2138 ct.fr.WriteGoAway(5, ErrCodeNo, []byte(goAwayDebugData))
2139 ct.fr.WriteGoAway(5, goAwayErrCode, nil)
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -07002140 ct.sc.(*net.TCPConn).CloseWrite()
Brad Fitzpatrickef2e00e2016-06-28 16:00:16 -07002141 <-clientDone
2142 return nil
2143 }
2144 }
2145 ct.run()
2146}
Brad Fitzpatrick6a513af2016-07-26 10:19:14 +02002147
2148// See golang.org/issue/16481
2149func TestTransportReturnsUnusedFlowControl(t *testing.T) {
2150 ct := newClientTester(t)
2151
2152 clientClosed := make(chan bool, 1)
2153 serverWroteBody := make(chan bool, 1)
2154
2155 ct.client = func() error {
2156 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2157 res, err := ct.tr.RoundTrip(req)
2158 if err != nil {
2159 return err
2160 }
2161 <-serverWroteBody
2162
2163 if n, err := res.Body.Read(make([]byte, 1)); err != nil || n != 1 {
2164 return fmt.Errorf("body read = %v, %v; want 1, nil", n, err)
2165 }
2166 res.Body.Close() // leaving 4999 bytes unread
2167 clientClosed <- true
2168
2169 return nil
2170 }
2171 ct.server = func() error {
2172 ct.greet()
2173
2174 var hf *HeadersFrame
2175 for {
2176 f, err := ct.fr.ReadFrame()
2177 if err != nil {
2178 return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
2179 }
2180 switch f.(type) {
2181 case *WindowUpdateFrame, *SettingsFrame:
2182 continue
2183 }
2184 var ok bool
2185 hf, ok = f.(*HeadersFrame)
2186 if !ok {
2187 return fmt.Errorf("Got %T; want HeadersFrame", f)
2188 }
2189 break
2190 }
2191
2192 var buf bytes.Buffer
2193 enc := hpack.NewEncoder(&buf)
2194 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2195 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"})
2196 ct.fr.WriteHeaders(HeadersFrameParam{
2197 StreamID: hf.StreamID,
2198 EndHeaders: true,
2199 EndStream: false,
2200 BlockFragment: buf.Bytes(),
2201 })
2202 ct.fr.WriteData(hf.StreamID, false, make([]byte, 5000)) // without ending stream
2203 serverWroteBody <- true
2204
2205 <-clientClosed
2206
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -07002207 waitingFor := "RSTStreamFrame"
2208 for {
2209 f, err := ct.fr.ReadFrame()
2210 if err != nil {
2211 return fmt.Errorf("ReadFrame while waiting for %s: %v", waitingFor, err)
2212 }
2213 if _, ok := f.(*SettingsFrame); ok {
2214 continue
2215 }
2216 switch waitingFor {
2217 case "RSTStreamFrame":
2218 if rf, ok := f.(*RSTStreamFrame); !ok || rf.ErrCode != ErrCodeCancel {
2219 return fmt.Errorf("Expected a WindowUpdateFrame with code cancel; got %v", summarizeFrame(f))
2220 }
2221 waitingFor = "WindowUpdateFrame"
2222 case "WindowUpdateFrame":
2223 if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != 4999 {
2224 return fmt.Errorf("Expected WindowUpdateFrame for 4999 bytes; got %v", summarizeFrame(f))
2225 }
2226 return nil
2227 }
Brad Fitzpatrick6a513af2016-07-26 10:19:14 +02002228 }
Brad Fitzpatrick6a513af2016-07-26 10:19:14 +02002229 }
2230 ct.run()
2231}
Brad Fitzpatrick35028a42016-07-31 15:09:09 -07002232
Brad Fitzpatrick075e1912016-08-05 06:12:51 +00002233// Issue 16612: adjust flow control on open streams when transport
2234// receives SETTINGS with INITIAL_WINDOW_SIZE from server.
2235func TestTransportAdjustsFlowControl(t *testing.T) {
2236 ct := newClientTester(t)
2237 clientDone := make(chan struct{})
2238
2239 const bodySize = 1 << 20
2240
2241 ct.client = func() error {
2242 defer ct.cc.(*net.TCPConn).CloseWrite()
2243 defer close(clientDone)
2244
2245 req, _ := http.NewRequest("POST", "https://dummy.tld/", struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
2246 res, err := ct.tr.RoundTrip(req)
2247 if err != nil {
2248 return err
2249 }
2250 res.Body.Close()
2251 return nil
2252 }
2253 ct.server = func() error {
2254 _, err := io.ReadFull(ct.sc, make([]byte, len(ClientPreface)))
2255 if err != nil {
2256 return fmt.Errorf("reading client preface: %v", err)
2257 }
2258
2259 var gotBytes int64
2260 var sentSettings bool
2261 for {
2262 f, err := ct.fr.ReadFrame()
2263 if err != nil {
2264 select {
2265 case <-clientDone:
2266 return nil
2267 default:
2268 return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
2269 }
2270 }
2271 switch f := f.(type) {
2272 case *DataFrame:
2273 gotBytes += int64(len(f.Data()))
2274 // After we've got half the client's
2275 // initial flow control window's worth
2276 // of request body data, give it just
2277 // enough flow control to finish.
2278 if gotBytes >= initialWindowSize/2 && !sentSettings {
2279 sentSettings = true
2280
2281 ct.fr.WriteSettings(Setting{ID: SettingInitialWindowSize, Val: bodySize})
2282 ct.fr.WriteWindowUpdate(0, bodySize)
2283 ct.fr.WriteSettingsAck()
2284 }
2285
2286 if f.StreamEnded() {
2287 var buf bytes.Buffer
2288 enc := hpack.NewEncoder(&buf)
2289 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2290 ct.fr.WriteHeaders(HeadersFrameParam{
2291 StreamID: f.StreamID,
2292 EndHeaders: true,
2293 EndStream: true,
2294 BlockFragment: buf.Bytes(),
2295 })
2296 }
2297 }
2298 }
2299 }
2300 ct.run()
2301}
2302
Brad Fitzpatrick35028a42016-07-31 15:09:09 -07002303// See golang.org/issue/16556
2304func TestTransportReturnsDataPaddingFlowControl(t *testing.T) {
2305 ct := newClientTester(t)
2306
2307 unblockClient := make(chan bool, 1)
2308
2309 ct.client = func() error {
2310 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2311 res, err := ct.tr.RoundTrip(req)
2312 if err != nil {
2313 return err
2314 }
2315 defer res.Body.Close()
2316 <-unblockClient
2317 return nil
2318 }
2319 ct.server = func() error {
2320 ct.greet()
2321
2322 var hf *HeadersFrame
2323 for {
2324 f, err := ct.fr.ReadFrame()
2325 if err != nil {
2326 return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
2327 }
2328 switch f.(type) {
2329 case *WindowUpdateFrame, *SettingsFrame:
2330 continue
2331 }
2332 var ok bool
2333 hf, ok = f.(*HeadersFrame)
2334 if !ok {
2335 return fmt.Errorf("Got %T; want HeadersFrame", f)
2336 }
2337 break
2338 }
2339
2340 var buf bytes.Buffer
2341 enc := hpack.NewEncoder(&buf)
2342 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2343 enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"})
2344 ct.fr.WriteHeaders(HeadersFrameParam{
2345 StreamID: hf.StreamID,
2346 EndHeaders: true,
2347 EndStream: false,
2348 BlockFragment: buf.Bytes(),
2349 })
2350 pad := []byte("12345")
2351 ct.fr.WriteDataPadded(hf.StreamID, false, make([]byte, 5000), pad) // without ending stream
2352
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -07002353 f, err := ct.readNonSettingsFrame()
Brad Fitzpatrick35028a42016-07-31 15:09:09 -07002354 if err != nil {
2355 return fmt.Errorf("ReadFrame while waiting for first WindowUpdateFrame: %v", err)
2356 }
2357 wantBack := uint32(len(pad)) + 1 // one byte for the length of the padding
2358 if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID != 0 {
2359 return fmt.Errorf("Expected conn WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f))
2360 }
2361
Brad Fitzpatrick28d1bd42016-07-30 13:25:50 -07002362 f, err = ct.readNonSettingsFrame()
Brad Fitzpatrick35028a42016-07-31 15:09:09 -07002363 if err != nil {
2364 return fmt.Errorf("ReadFrame while waiting for second WindowUpdateFrame: %v", err)
2365 }
2366 if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID == 0 {
2367 return fmt.Errorf("Expected stream WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f))
2368 }
2369 unblockClient <- true
2370 return nil
2371 }
2372 ct.run()
2373}
Brad Fitzpatricke2ba55e2016-08-02 15:44:32 +00002374
2375// golang.org/issue/16572 -- RoundTrip shouldn't hang when it gets a
2376// StreamError as a result of the response HEADERS
2377func TestTransportReturnsErrorOnBadResponseHeaders(t *testing.T) {
2378 ct := newClientTester(t)
2379
2380 ct.client = func() error {
2381 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2382 res, err := ct.tr.RoundTrip(req)
2383 if err == nil {
2384 res.Body.Close()
2385 return errors.New("unexpected successful GET")
2386 }
2387 want := StreamError{1, ErrCodeProtocol, headerFieldNameError(" content-type")}
2388 if !reflect.DeepEqual(want, err) {
2389 t.Errorf("RoundTrip error = %#v; want %#v", err, want)
2390 }
2391 return nil
2392 }
2393 ct.server = func() error {
2394 ct.greet()
2395
2396 hf, err := ct.firstHeaders()
2397 if err != nil {
2398 return err
2399 }
2400
2401 var buf bytes.Buffer
2402 enc := hpack.NewEncoder(&buf)
2403 enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
2404 enc.WriteField(hpack.HeaderField{Name: " content-type", Value: "bogus"}) // bogus spaces
2405 ct.fr.WriteHeaders(HeadersFrameParam{
2406 StreamID: hf.StreamID,
2407 EndHeaders: true,
2408 EndStream: false,
2409 BlockFragment: buf.Bytes(),
2410 })
2411
2412 for {
2413 fr, err := ct.readFrame()
2414 if err != nil {
2415 return fmt.Errorf("error waiting for RST_STREAM from client: %v", err)
2416 }
2417 if _, ok := fr.(*SettingsFrame); ok {
2418 continue
2419 }
2420 if rst, ok := fr.(*RSTStreamFrame); !ok || rst.StreamID != 1 || rst.ErrCode != ErrCodeProtocol {
2421 t.Errorf("Frame = %v; want RST_STREAM for stream 1 with ErrCodeProtocol", summarizeFrame(fr))
2422 }
2423 break
2424 }
2425
2426 return nil
2427 }
2428 ct.run()
2429}
Brad Fitzpatrick7394c112016-08-19 13:57:39 -07002430
2431// byteAndEOFReader returns is in an io.Reader which reads one byte
2432// (the underlying byte) and io.EOF at once in its Read call.
2433type byteAndEOFReader byte
2434
2435func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
2436 if len(p) == 0 {
2437 panic("unexpected useless call")
2438 }
2439 p[0] = byte(b)
2440 return 1, io.EOF
2441}
2442
2443// Issue 16788: the Transport had a regression where it started
2444// sending a spurious DATA frame with a duplicate END_STREAM bit after
2445// the request body writer goroutine had already read an EOF from the
2446// Request.Body and included the END_STREAM on a data-carrying DATA
2447// frame.
2448//
2449// Notably, to trigger this, the requests need to use a Request.Body
2450// which returns (non-0, io.EOF) and also needs to set the ContentLength
2451// explicitly.
2452func TestTransportBodyDoubleEndStream(t *testing.T) {
2453 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
2454 // Nothing.
2455 }, optOnlyServer)
2456 defer st.Close()
2457
2458 tr := &Transport{TLSClientConfig: tlsConfigInsecure}
2459 defer tr.CloseIdleConnections()
2460
2461 for i := 0; i < 2; i++ {
2462 req, _ := http.NewRequest("POST", st.ts.URL, byteAndEOFReader('a'))
2463 req.ContentLength = 1
2464 res, err := tr.RoundTrip(req)
2465 if err != nil {
2466 t.Fatalf("failure on req %d: %v", i+1, err)
2467 }
2468 defer res.Body.Close()
2469 }
2470}
Brad Fitzpatrick3a1f9ef2016-08-23 20:08:20 +00002471
2472// golangorg/issue/16847
2473func TestTransportRequestPathPseudo(t *testing.T) {
2474 type result struct {
2475 path string
2476 err string
2477 }
2478 tests := []struct {
2479 req *http.Request
2480 want result
2481 }{
2482 0: {
2483 req: &http.Request{
2484 Method: "GET",
2485 URL: &url.URL{
2486 Host: "foo.com",
2487 Path: "/foo",
2488 },
2489 },
2490 want: result{path: "/foo"},
2491 },
2492 // I guess we just don't let users request "//foo" as
2493 // a path, since it's illegal to start with two
2494 // slashes....
2495 1: {
2496 req: &http.Request{
2497 Method: "GET",
2498 URL: &url.URL{
2499 Host: "foo.com",
2500 Path: "//foo",
2501 },
2502 },
2503 want: result{err: `invalid request :path "//foo"`},
2504 },
2505
2506 // Opaque with //$Matching_Hostname/path
2507 2: {
2508 req: &http.Request{
2509 Method: "GET",
2510 URL: &url.URL{
2511 Scheme: "https",
2512 Opaque: "//foo.com/path",
2513 Host: "foo.com",
2514 Path: "/ignored",
2515 },
2516 },
2517 want: result{path: "/path"},
2518 },
2519
2520 // Opaque with some other Request.Host instead:
2521 3: {
2522 req: &http.Request{
2523 Method: "GET",
2524 Host: "bar.com",
2525 URL: &url.URL{
2526 Scheme: "https",
2527 Opaque: "//bar.com/path",
2528 Host: "foo.com",
2529 Path: "/ignored",
2530 },
2531 },
2532 want: result{path: "/path"},
2533 },
2534
2535 // Opaque without the leading "//":
2536 4: {
2537 req: &http.Request{
2538 Method: "GET",
2539 URL: &url.URL{
2540 Opaque: "/path",
2541 Host: "foo.com",
2542 Path: "/ignored",
2543 },
2544 },
2545 want: result{path: "/path"},
2546 },
2547
2548 // Opaque we can't handle:
2549 5: {
2550 req: &http.Request{
2551 Method: "GET",
2552 URL: &url.URL{
2553 Scheme: "https",
2554 Opaque: "//unknown_host/path",
2555 Host: "foo.com",
2556 Path: "/ignored",
2557 },
2558 },
2559 want: result{err: `invalid request :path "https://unknown_host/path" from URL.Opaque = "//unknown_host/path"`},
2560 },
2561
2562 // A CONNECT request:
2563 6: {
2564 req: &http.Request{
2565 Method: "CONNECT",
2566 URL: &url.URL{
2567 Host: "foo.com",
2568 },
2569 },
2570 want: result{},
2571 },
2572 }
2573 for i, tt := range tests {
2574 cc := &ClientConn{}
2575 cc.henc = hpack.NewEncoder(&cc.hbuf)
2576 cc.mu.Lock()
2577 hdrs, err := cc.encodeHeaders(tt.req, false, "", -1)
2578 cc.mu.Unlock()
2579 var got result
2580 hpackDec := hpack.NewDecoder(initialHeaderTableSize, func(f hpack.HeaderField) {
2581 if f.Name == ":path" {
2582 got.path = f.Value
2583 }
2584 })
2585 if err != nil {
2586 got.err = err.Error()
2587 } else if len(hdrs) > 0 {
2588 if _, err := hpackDec.Write(hdrs); err != nil {
2589 t.Errorf("%d. bogus hpack: %v", i, err)
2590 continue
2591 }
2592 }
2593 if got != tt.want {
2594 t.Errorf("%d. got %+v; want %+v", i, got, tt.want)
2595 }
2596
2597 }
2598
2599}