transport_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package http2
  5. import (
  6. "crypto/tls"
  7. "flag"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "math/rand"
  12. "net"
  13. "net/http"
  14. "net/url"
  15. "os"
  16. "reflect"
  17. "strings"
  18. "sync"
  19. "testing"
  20. "time"
  21. )
  22. var (
  23. extNet = flag.Bool("extnet", false, "do external network tests")
  24. transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport")
  25. insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove?
  26. )
  27. var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true}
  28. func TestTransportExternal(t *testing.T) {
  29. if !*extNet {
  30. t.Skip("skipping external network test")
  31. }
  32. req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil)
  33. rt := &Transport{TLSClientConfig: tlsConfigInsecure}
  34. res, err := rt.RoundTrip(req)
  35. if err != nil {
  36. t.Fatalf("%v", err)
  37. }
  38. res.Write(os.Stdout)
  39. }
  40. func TestTransport(t *testing.T) {
  41. const body = "sup"
  42. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  43. io.WriteString(w, body)
  44. }, optOnlyServer)
  45. defer st.Close()
  46. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  47. defer tr.CloseIdleConnections()
  48. req, err := http.NewRequest("GET", st.ts.URL, nil)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. res, err := tr.RoundTrip(req)
  53. if err != nil {
  54. t.Fatal(err)
  55. }
  56. defer res.Body.Close()
  57. t.Logf("Got res: %+v", res)
  58. if g, w := res.StatusCode, 200; g != w {
  59. t.Errorf("StatusCode = %v; want %v", g, w)
  60. }
  61. if g, w := res.Status, "200 OK"; g != w {
  62. t.Errorf("Status = %q; want %q", g, w)
  63. }
  64. wantHeader := http.Header{
  65. "Content-Length": []string{"3"},
  66. "Content-Type": []string{"text/plain; charset=utf-8"},
  67. "Date": []string{"XXX"}, // see cleanDate
  68. }
  69. cleanDate(res)
  70. if !reflect.DeepEqual(res.Header, wantHeader) {
  71. t.Errorf("res Header = %v; want %v", res.Header, wantHeader)
  72. }
  73. if res.Request != req {
  74. t.Errorf("Response.Request = %p; want %p", res.Request, req)
  75. }
  76. if res.TLS == nil {
  77. t.Error("Response.TLS = nil; want non-nil")
  78. }
  79. slurp, err := ioutil.ReadAll(res.Body)
  80. if err != nil {
  81. t.Errorf("Body read: %v", err)
  82. } else if string(slurp) != body {
  83. t.Errorf("Body = %q; want %q", slurp, body)
  84. }
  85. }
  86. func TestTransportReusesConns(t *testing.T) {
  87. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  88. io.WriteString(w, r.RemoteAddr)
  89. }, optOnlyServer)
  90. defer st.Close()
  91. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  92. defer tr.CloseIdleConnections()
  93. get := func() string {
  94. req, err := http.NewRequest("GET", st.ts.URL, nil)
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. res, err := tr.RoundTrip(req)
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. defer res.Body.Close()
  103. slurp, err := ioutil.ReadAll(res.Body)
  104. if err != nil {
  105. t.Fatalf("Body read: %v", err)
  106. }
  107. addr := strings.TrimSpace(string(slurp))
  108. if addr == "" {
  109. t.Fatalf("didn't get an addr in response")
  110. }
  111. return addr
  112. }
  113. first := get()
  114. second := get()
  115. if first != second {
  116. t.Errorf("first and second responses were on different connections: %q vs %q", first, second)
  117. }
  118. }
  119. // Tests that the Transport only keeps one pending dial open per destination address.
  120. // https://golang.org/issue/13397
  121. func TestTransportGroupsPendingDials(t *testing.T) {
  122. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  123. io.WriteString(w, r.RemoteAddr)
  124. }, optOnlyServer)
  125. defer st.Close()
  126. tr := &Transport{
  127. TLSClientConfig: tlsConfigInsecure,
  128. }
  129. defer tr.CloseIdleConnections()
  130. var (
  131. mu sync.Mutex
  132. dials = map[string]int{}
  133. )
  134. var wg sync.WaitGroup
  135. for i := 0; i < 10; i++ {
  136. wg.Add(1)
  137. go func() {
  138. defer wg.Done()
  139. req, err := http.NewRequest("GET", st.ts.URL, nil)
  140. if err != nil {
  141. t.Error(err)
  142. return
  143. }
  144. res, err := tr.RoundTrip(req)
  145. if err != nil {
  146. t.Error(err)
  147. return
  148. }
  149. defer res.Body.Close()
  150. slurp, err := ioutil.ReadAll(res.Body)
  151. if err != nil {
  152. t.Errorf("Body read: %v", err)
  153. }
  154. addr := strings.TrimSpace(string(slurp))
  155. if addr == "" {
  156. t.Errorf("didn't get an addr in response")
  157. }
  158. mu.Lock()
  159. dials[addr]++
  160. mu.Unlock()
  161. }()
  162. }
  163. wg.Wait()
  164. if len(dials) != 1 {
  165. t.Errorf("saw %d dials; want 1: %v", len(dials), dials)
  166. }
  167. tr.CloseIdleConnections()
  168. if err := retry(50, 10*time.Millisecond, func() error {
  169. cp, ok := tr.connPool().(*clientConnPool)
  170. if !ok {
  171. return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool())
  172. }
  173. if len(cp.dialing) != 0 {
  174. return fmt.Errorf("dialing map = %v; want empty", cp.dialing)
  175. }
  176. if len(cp.conns) != 0 {
  177. return fmt.Errorf("conns = %v; want empty", cp.conns)
  178. }
  179. if len(cp.keys) != 0 {
  180. return fmt.Errorf("keys = %v; want empty", cp.keys)
  181. }
  182. return nil
  183. }); err != nil {
  184. t.Error("State of pool after CloseIdleConnections: %v", err)
  185. }
  186. }
  187. func retry(tries int, delay time.Duration, fn func() error) error {
  188. var err error
  189. for i := 0; i < tries; i++ {
  190. err = fn()
  191. if err == nil {
  192. return nil
  193. }
  194. time.Sleep(delay)
  195. }
  196. return err
  197. }
  198. func TestTransportAbortClosesPipes(t *testing.T) {
  199. shutdown := make(chan struct{})
  200. st := newServerTester(t,
  201. func(w http.ResponseWriter, r *http.Request) {
  202. w.(http.Flusher).Flush()
  203. <-shutdown
  204. },
  205. optOnlyServer,
  206. )
  207. defer st.Close()
  208. defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
  209. done := make(chan struct{})
  210. requestMade := make(chan struct{})
  211. go func() {
  212. defer close(done)
  213. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  214. req, err := http.NewRequest("GET", st.ts.URL, nil)
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. res, err := tr.RoundTrip(req)
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. defer res.Body.Close()
  223. close(requestMade)
  224. _, err = ioutil.ReadAll(res.Body)
  225. if err == nil {
  226. t.Error("expected error from res.Body.Read")
  227. }
  228. }()
  229. <-requestMade
  230. // Now force the serve loop to end, via closing the connection.
  231. st.closeConn()
  232. // deadlock? that's a bug.
  233. select {
  234. case <-done:
  235. case <-time.After(3 * time.Second):
  236. t.Fatal("timeout")
  237. }
  238. }
  239. // TODO: merge this with TestTransportBody to make TestTransportRequest? This
  240. // could be a table-driven test with extra goodies.
  241. func TestTransportPath(t *testing.T) {
  242. gotc := make(chan *url.URL, 1)
  243. st := newServerTester(t,
  244. func(w http.ResponseWriter, r *http.Request) {
  245. gotc <- r.URL
  246. },
  247. optOnlyServer,
  248. )
  249. defer st.Close()
  250. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  251. defer tr.CloseIdleConnections()
  252. const (
  253. path = "/testpath"
  254. query = "q=1"
  255. )
  256. surl := st.ts.URL + path + "?" + query
  257. req, err := http.NewRequest("POST", surl, nil)
  258. if err != nil {
  259. t.Fatal(err)
  260. }
  261. c := &http.Client{Transport: tr}
  262. res, err := c.Do(req)
  263. if err != nil {
  264. t.Fatal(err)
  265. }
  266. defer res.Body.Close()
  267. got := <-gotc
  268. if got.Path != path {
  269. t.Errorf("Read Path = %q; want %q", got.Path, path)
  270. }
  271. if got.RawQuery != query {
  272. t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
  273. }
  274. }
  275. func randString(n int) string {
  276. rnd := rand.New(rand.NewSource(int64(n)))
  277. b := make([]byte, n)
  278. for i := range b {
  279. b[i] = byte(rnd.Intn(256))
  280. }
  281. return string(b)
  282. }
  283. var bodyTests = []struct {
  284. body string
  285. noContentLen bool
  286. }{
  287. {body: "some message"},
  288. {body: "some message", noContentLen: true},
  289. {body: ""},
  290. {body: "", noContentLen: true},
  291. {body: strings.Repeat("a", 1<<20), noContentLen: true},
  292. {body: strings.Repeat("a", 1<<20)},
  293. {body: randString(16<<10 - 1)},
  294. {body: randString(16 << 10)},
  295. {body: randString(16<<10 + 1)},
  296. {body: randString(512<<10 - 1)},
  297. {body: randString(512 << 10)},
  298. {body: randString(512<<10 + 1)},
  299. {body: randString(1<<20 - 1)},
  300. {body: randString(1 << 20)},
  301. {body: randString(1<<20 + 2)},
  302. }
  303. func TestTransportBody(t *testing.T) {
  304. gotc := make(chan interface{}, 1)
  305. st := newServerTester(t,
  306. func(w http.ResponseWriter, r *http.Request) {
  307. slurp, err := ioutil.ReadAll(r.Body)
  308. if err != nil {
  309. gotc <- err
  310. } else {
  311. gotc <- string(slurp)
  312. }
  313. },
  314. optOnlyServer,
  315. )
  316. defer st.Close()
  317. for i, tt := range bodyTests {
  318. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  319. defer tr.CloseIdleConnections()
  320. var body io.Reader = strings.NewReader(tt.body)
  321. if tt.noContentLen {
  322. body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
  323. }
  324. req, err := http.NewRequest("POST", st.ts.URL, body)
  325. if err != nil {
  326. t.Fatalf("#%d: %v", i, err)
  327. }
  328. c := &http.Client{Transport: tr}
  329. res, err := c.Do(req)
  330. if err != nil {
  331. t.Fatalf("#%d: %v", i, err)
  332. }
  333. defer res.Body.Close()
  334. got := <-gotc
  335. if err, ok := got.(error); ok {
  336. t.Fatalf("#%d: %v", i, err)
  337. } else if got.(string) != tt.body {
  338. got := got.(string)
  339. 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))
  340. }
  341. }
  342. }
  343. func shortString(v string) string {
  344. const maxLen = 100
  345. if len(v) <= maxLen {
  346. return v
  347. }
  348. return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
  349. }
  350. func TestTransportDialTLS(t *testing.T) {
  351. var mu sync.Mutex // guards following
  352. var gotReq, didDial bool
  353. ts := newServerTester(t,
  354. func(w http.ResponseWriter, r *http.Request) {
  355. mu.Lock()
  356. gotReq = true
  357. mu.Unlock()
  358. },
  359. optOnlyServer,
  360. )
  361. defer ts.Close()
  362. tr := &Transport{
  363. DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
  364. mu.Lock()
  365. didDial = true
  366. mu.Unlock()
  367. cfg.InsecureSkipVerify = true
  368. c, err := tls.Dial(netw, addr, cfg)
  369. if err != nil {
  370. return nil, err
  371. }
  372. return c, c.Handshake()
  373. },
  374. }
  375. defer tr.CloseIdleConnections()
  376. client := &http.Client{Transport: tr}
  377. res, err := client.Get(ts.ts.URL)
  378. if err != nil {
  379. t.Fatal(err)
  380. }
  381. res.Body.Close()
  382. mu.Lock()
  383. if !gotReq {
  384. t.Error("didn't get request")
  385. }
  386. if !didDial {
  387. t.Error("didn't use dial hook")
  388. }
  389. }
  390. func TestConfigureTransport(t *testing.T) {
  391. t1 := &http.Transport{}
  392. err := ConfigureTransport(t1)
  393. if err == errTransportVersion {
  394. t.Skip(err)
  395. }
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) {
  400. // Laziness, to avoid buildtags.
  401. t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got)
  402. }
  403. if t1.TLSClientConfig == nil {
  404. t.Errorf("nil t1.TLSClientConfig")
  405. } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, []string{"h2"}) {
  406. t.Errorf("TLSClientConfig.NextProtos = %q; want just 'h2'", t1.TLSClientConfig.NextProtos)
  407. }
  408. if err := ConfigureTransport(t1); err == nil {
  409. t.Error("unexpected success on second call to ConfigureTransport")
  410. }
  411. // And does it work?
  412. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  413. io.WriteString(w, r.Proto)
  414. }, optOnlyServer)
  415. defer st.Close()
  416. t1.TLSClientConfig.InsecureSkipVerify = true
  417. c := &http.Client{Transport: t1}
  418. res, err := c.Get(st.ts.URL)
  419. if err != nil {
  420. t.Fatal(err)
  421. }
  422. slurp, err := ioutil.ReadAll(res.Body)
  423. if err != nil {
  424. t.Fatal(err)
  425. }
  426. if got, want := string(slurp), "HTTP/2.0"; got != want {
  427. t.Errorf("body = %q; want %q", got, want)
  428. }
  429. }