transport_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. }
  68. if !reflect.DeepEqual(res.Header, wantHeader) {
  69. t.Errorf("res Header = %v; want %v", res.Header, wantHeader)
  70. }
  71. if res.Request != req {
  72. t.Errorf("Response.Request = %p; want %p", res.Request, req)
  73. }
  74. if res.TLS == nil {
  75. t.Error("Response.TLS = nil; want non-nil")
  76. }
  77. slurp, err := ioutil.ReadAll(res.Body)
  78. if err != nil {
  79. t.Errorf("Body read: %v", err)
  80. } else if string(slurp) != body {
  81. t.Errorf("Body = %q; want %q", slurp, body)
  82. }
  83. }
  84. func TestTransportReusesConns(t *testing.T) {
  85. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  86. io.WriteString(w, r.RemoteAddr)
  87. }, optOnlyServer)
  88. defer st.Close()
  89. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  90. defer tr.CloseIdleConnections()
  91. get := func() string {
  92. req, err := http.NewRequest("GET", st.ts.URL, nil)
  93. if err != nil {
  94. t.Fatal(err)
  95. }
  96. res, err := tr.RoundTrip(req)
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. defer res.Body.Close()
  101. slurp, err := ioutil.ReadAll(res.Body)
  102. if err != nil {
  103. t.Fatalf("Body read: %v", err)
  104. }
  105. addr := strings.TrimSpace(string(slurp))
  106. if addr == "" {
  107. t.Fatalf("didn't get an addr in response")
  108. }
  109. return addr
  110. }
  111. first := get()
  112. second := get()
  113. if first != second {
  114. t.Errorf("first and second responses were on different connections: %q vs %q", first, second)
  115. }
  116. }
  117. func TestTransportAbortClosesPipes(t *testing.T) {
  118. shutdown := make(chan struct{})
  119. st := newServerTester(t,
  120. func(w http.ResponseWriter, r *http.Request) {
  121. w.(http.Flusher).Flush()
  122. <-shutdown
  123. },
  124. optOnlyServer,
  125. )
  126. defer st.Close()
  127. defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
  128. done := make(chan struct{})
  129. requestMade := make(chan struct{})
  130. go func() {
  131. defer close(done)
  132. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  133. req, err := http.NewRequest("GET", st.ts.URL, nil)
  134. if err != nil {
  135. t.Fatal(err)
  136. }
  137. res, err := tr.RoundTrip(req)
  138. if err != nil {
  139. t.Fatal(err)
  140. }
  141. defer res.Body.Close()
  142. close(requestMade)
  143. _, err = ioutil.ReadAll(res.Body)
  144. if err == nil {
  145. t.Error("expected error from res.Body.Read")
  146. }
  147. }()
  148. <-requestMade
  149. // Now force the serve loop to end, via closing the connection.
  150. st.closeConn()
  151. // deadlock? that's a bug.
  152. select {
  153. case <-done:
  154. case <-time.After(3 * time.Second):
  155. t.Fatal("timeout")
  156. }
  157. }
  158. // TODO: merge this with TestTransportBody to make TestTransportRequest? This
  159. // could be a table-driven test with extra goodies.
  160. func TestTransportPath(t *testing.T) {
  161. gotc := make(chan *url.URL, 1)
  162. st := newServerTester(t,
  163. func(w http.ResponseWriter, r *http.Request) {
  164. gotc <- r.URL
  165. },
  166. optOnlyServer,
  167. )
  168. defer st.Close()
  169. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  170. defer tr.CloseIdleConnections()
  171. const (
  172. path = "/testpath"
  173. query = "q=1"
  174. )
  175. surl := st.ts.URL + path + "?" + query
  176. req, err := http.NewRequest("POST", surl, nil)
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. c := &http.Client{Transport: tr}
  181. res, err := c.Do(req)
  182. if err != nil {
  183. t.Fatal(err)
  184. }
  185. defer res.Body.Close()
  186. got := <-gotc
  187. if got.Path != path {
  188. t.Errorf("Read Path = %q; want %q", got.Path, path)
  189. }
  190. if got.RawQuery != query {
  191. t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
  192. }
  193. }
  194. func randString(n int) string {
  195. rnd := rand.New(rand.NewSource(int64(n)))
  196. b := make([]byte, n)
  197. for i := range b {
  198. b[i] = byte(rnd.Intn(256))
  199. }
  200. return string(b)
  201. }
  202. var bodyTests = []struct {
  203. body string
  204. noContentLen bool
  205. }{
  206. {body: "some message"},
  207. {body: "some message", noContentLen: true},
  208. {body: ""},
  209. {body: "", noContentLen: true},
  210. {body: strings.Repeat("a", 1<<20), noContentLen: true},
  211. {body: strings.Repeat("a", 1<<20)},
  212. {body: randString(16<<10 - 1)},
  213. {body: randString(16 << 10)},
  214. {body: randString(16<<10 + 1)},
  215. {body: randString(512<<10 - 1)},
  216. {body: randString(512 << 10)},
  217. {body: randString(512<<10 + 1)},
  218. {body: randString(1<<20 - 1)},
  219. {body: randString(1 << 20)},
  220. {body: randString(1<<20 + 2)},
  221. }
  222. func TestTransportBody(t *testing.T) {
  223. gotc := make(chan interface{}, 1)
  224. st := newServerTester(t,
  225. func(w http.ResponseWriter, r *http.Request) {
  226. slurp, err := ioutil.ReadAll(r.Body)
  227. if err != nil {
  228. gotc <- err
  229. } else {
  230. gotc <- string(slurp)
  231. }
  232. },
  233. optOnlyServer,
  234. )
  235. defer st.Close()
  236. for i, tt := range bodyTests {
  237. tr := &Transport{TLSClientConfig: tlsConfigInsecure}
  238. defer tr.CloseIdleConnections()
  239. var body io.Reader = strings.NewReader(tt.body)
  240. if tt.noContentLen {
  241. body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
  242. }
  243. req, err := http.NewRequest("POST", st.ts.URL, body)
  244. if err != nil {
  245. t.Fatalf("#%d: %v", i, err)
  246. }
  247. c := &http.Client{Transport: tr}
  248. res, err := c.Do(req)
  249. if err != nil {
  250. t.Fatalf("#%d: %v", i, err)
  251. }
  252. defer res.Body.Close()
  253. got := <-gotc
  254. if err, ok := got.(error); ok {
  255. t.Fatalf("#%d: %v", i, err)
  256. } else if got.(string) != tt.body {
  257. got := got.(string)
  258. 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))
  259. }
  260. }
  261. }
  262. func shortString(v string) string {
  263. const maxLen = 100
  264. if len(v) <= maxLen {
  265. return v
  266. }
  267. return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
  268. }
  269. func TestTransportDialTLS(t *testing.T) {
  270. var mu sync.Mutex // guards following
  271. var gotReq, didDial bool
  272. ts := newServerTester(t,
  273. func(w http.ResponseWriter, r *http.Request) {
  274. mu.Lock()
  275. gotReq = true
  276. mu.Unlock()
  277. },
  278. optOnlyServer,
  279. )
  280. defer ts.Close()
  281. tr := &Transport{
  282. DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
  283. mu.Lock()
  284. didDial = true
  285. mu.Unlock()
  286. cfg.InsecureSkipVerify = true
  287. c, err := tls.Dial(netw, addr, cfg)
  288. if err != nil {
  289. return nil, err
  290. }
  291. return c, c.Handshake()
  292. },
  293. }
  294. defer tr.CloseIdleConnections()
  295. client := &http.Client{Transport: tr}
  296. res, err := client.Get(ts.ts.URL)
  297. if err != nil {
  298. t.Fatal(err)
  299. }
  300. res.Body.Close()
  301. mu.Lock()
  302. if !gotReq {
  303. t.Error("didn't get request")
  304. }
  305. if !didDial {
  306. t.Error("didn't use dial hook")
  307. }
  308. }