transport_internal_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2016 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. // White-box tests for transport.go (in package http instead of http_test).
  5. package http
  6. import (
  7. "bytes"
  8. "crypto/tls"
  9. "errors"
  10. "io"
  11. "net"
  12. "net/http/internal/testcert"
  13. "strings"
  14. "testing"
  15. )
  16. // Issue 15446: incorrect wrapping of errors when server closes an idle connection.
  17. func TestTransportPersistConnReadLoopEOF(t *testing.T) {
  18. ln := newLocalListener(t)
  19. defer ln.Close()
  20. connc := make(chan net.Conn, 1)
  21. go func() {
  22. defer close(connc)
  23. c, err := ln.Accept()
  24. if err != nil {
  25. t.Error(err)
  26. return
  27. }
  28. connc <- c
  29. }()
  30. tr := new(Transport)
  31. req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
  32. req = req.WithT(t)
  33. treq := &transportRequest{Request: req}
  34. cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
  35. pc, err := tr.getConn(treq, cm)
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. defer pc.close(errors.New("test over"))
  40. conn := <-connc
  41. if conn == nil {
  42. // Already called t.Error in the accept goroutine.
  43. return
  44. }
  45. conn.Close() // simulate the server hanging up on the client
  46. _, err = pc.roundTrip(treq)
  47. if !isNothingWrittenError(err) && !isTransportReadFromServerError(err) && err != errServerClosedIdle {
  48. t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle, transportReadFromServerError, or nothingWrittenError", err, err)
  49. }
  50. <-pc.closech
  51. err = pc.closed
  52. if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
  53. t.Errorf("pc.closed = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
  54. }
  55. }
  56. func isNothingWrittenError(err error) bool {
  57. _, ok := err.(nothingWrittenError)
  58. return ok
  59. }
  60. func isTransportReadFromServerError(err error) bool {
  61. _, ok := err.(transportReadFromServerError)
  62. return ok
  63. }
  64. func newLocalListener(t *testing.T) net.Listener {
  65. ln, err := net.Listen("tcp", "127.0.0.1:0")
  66. if err != nil {
  67. ln, err = net.Listen("tcp6", "[::1]:0")
  68. }
  69. if err != nil {
  70. t.Fatal(err)
  71. }
  72. return ln
  73. }
  74. func dummyRequest(method string) *Request {
  75. req, err := NewRequest(method, "http://fake.tld/", nil)
  76. if err != nil {
  77. panic(err)
  78. }
  79. return req
  80. }
  81. func dummyRequestWithBody(method string) *Request {
  82. req, err := NewRequest(method, "http://fake.tld/", strings.NewReader("foo"))
  83. if err != nil {
  84. panic(err)
  85. }
  86. return req
  87. }
  88. func dummyRequestWithBodyNoGetBody(method string) *Request {
  89. req := dummyRequestWithBody(method)
  90. req.GetBody = nil
  91. return req
  92. }
  93. // issue22091Error acts like a golang.org/x/net/http2.ErrNoCachedConn.
  94. type issue22091Error struct{}
  95. func (issue22091Error) IsHTTP2NoCachedConnError() {}
  96. func (issue22091Error) Error() string { return "issue22091Error" }
  97. func TestTransportShouldRetryRequest(t *testing.T) {
  98. tests := []struct {
  99. pc *persistConn
  100. req *Request
  101. err error
  102. want bool
  103. }{
  104. 0: {
  105. pc: &persistConn{reused: false},
  106. req: dummyRequest("POST"),
  107. err: nothingWrittenError{},
  108. want: false,
  109. },
  110. 1: {
  111. pc: &persistConn{reused: true},
  112. req: dummyRequest("POST"),
  113. err: nothingWrittenError{},
  114. want: true,
  115. },
  116. 2: {
  117. pc: &persistConn{reused: true},
  118. req: dummyRequest("POST"),
  119. err: http2ErrNoCachedConn,
  120. want: true,
  121. },
  122. 3: {
  123. pc: nil,
  124. req: nil,
  125. err: issue22091Error{}, // like an external http2ErrNoCachedConn
  126. want: true,
  127. },
  128. 4: {
  129. pc: &persistConn{reused: true},
  130. req: dummyRequest("POST"),
  131. err: errMissingHost,
  132. want: false,
  133. },
  134. 5: {
  135. pc: &persistConn{reused: true},
  136. req: dummyRequest("POST"),
  137. err: transportReadFromServerError{},
  138. want: false,
  139. },
  140. 6: {
  141. pc: &persistConn{reused: true},
  142. req: dummyRequest("GET"),
  143. err: transportReadFromServerError{},
  144. want: true,
  145. },
  146. 7: {
  147. pc: &persistConn{reused: true},
  148. req: dummyRequest("GET"),
  149. err: errServerClosedIdle,
  150. want: true,
  151. },
  152. 8: {
  153. pc: &persistConn{reused: true},
  154. req: dummyRequestWithBody("POST"),
  155. err: nothingWrittenError{},
  156. want: true,
  157. },
  158. 9: {
  159. pc: &persistConn{reused: true},
  160. req: dummyRequestWithBodyNoGetBody("POST"),
  161. err: nothingWrittenError{},
  162. want: false,
  163. },
  164. }
  165. for i, tt := range tests {
  166. got := tt.pc.shouldRetryRequest(tt.req, tt.err)
  167. if got != tt.want {
  168. t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
  169. }
  170. }
  171. }
  172. type roundTripFunc func(r *Request) (*Response, error)
  173. func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) {
  174. return f(r)
  175. }
  176. // Issue 25009
  177. func TestTransportBodyAltRewind(t *testing.T) {
  178. cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
  179. if err != nil {
  180. t.Fatal(err)
  181. }
  182. ln := newLocalListener(t)
  183. defer ln.Close()
  184. go func() {
  185. tln := tls.NewListener(ln, &tls.Config{
  186. NextProtos: []string{"foo"},
  187. Certificates: []tls.Certificate{cert},
  188. })
  189. for i := 0; i < 2; i++ {
  190. sc, err := tln.Accept()
  191. if err != nil {
  192. t.Error(err)
  193. return
  194. }
  195. if err := sc.(*tls.Conn).Handshake(); err != nil {
  196. t.Error(err)
  197. return
  198. }
  199. sc.Close()
  200. }
  201. }()
  202. addr := ln.Addr().String()
  203. req, _ := NewRequest("POST", "https://example.org/", bytes.NewBufferString("request"))
  204. roundTripped := false
  205. tr := &Transport{
  206. DisableKeepAlives: true,
  207. TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{
  208. "foo": func(authority string, c *tls.Conn) RoundTripper {
  209. return roundTripFunc(func(r *Request) (*Response, error) {
  210. n, _ := io.Copy(io.Discard, r.Body)
  211. if n == 0 {
  212. t.Error("body length is zero")
  213. }
  214. if roundTripped {
  215. return &Response{
  216. Body: NoBody,
  217. StatusCode: 200,
  218. }, nil
  219. }
  220. roundTripped = true
  221. return nil, http2noCachedConnError{}
  222. })
  223. },
  224. },
  225. DialTLS: func(_, _ string) (net.Conn, error) {
  226. tc, err := tls.Dial("tcp", addr, &tls.Config{
  227. InsecureSkipVerify: true,
  228. NextProtos: []string{"foo"},
  229. })
  230. if err != nil {
  231. return nil, err
  232. }
  233. if err := tc.Handshake(); err != nil {
  234. return nil, err
  235. }
  236. return tc, nil
  237. },
  238. }
  239. c := &Client{Transport: tr}
  240. _, err = c.Do(req)
  241. if err != nil {
  242. t.Error(err)
  243. }
  244. }