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