@@ -221,18 +221,48 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
221
221
return nil , err
222
222
}
223
223
224
- // Get the cached or newly-created connection to either the
225
- // host (for http or https), the http proxy, or the http proxy
226
- // pre-CONNECTed to https server. In any case, we'll be ready
227
- // to send it requests.
228
- pconn , err := t .getConn (req , cm )
229
- if err != nil {
230
- t .setReqCanceler (req , nil )
231
- req .closeBody ()
232
- return nil , err
233
- }
224
+ var pconn * persistConn
225
+ for {
226
+ // Get the cached or newly-created connection to either the
227
+ // host (for http or https), the http proxy, or the http proxy
228
+ // pre-CONNECTed to https server. In any case, we'll be ready
229
+ // to send it requests.
230
+ pconn , err = t .getConn (req , cm )
231
+ if err != nil {
232
+ t .setReqCanceler (req , nil )
233
+ req .closeBody ()
234
+ return nil , err
235
+ }
234
236
235
- return pconn .roundTrip (treq )
237
+ resp , err = pconn .roundTrip (treq )
238
+ if err != nil {
239
+ if brhErr , ok := err .(beforeRespHeaderError ); ok {
240
+ err = brhErr .error // unwrap the custom error in case we return it
241
+ if pconn .isReused () && (req .Method == "GET" || req .Method == "HEAD" ) {
242
+ // If we try to reuse a connection that the server is in the process of
243
+ // closing, we may end up successfully writing out our request (or a
244
+ // portion of our request) only to find a connection error when we try to
245
+ // read from (or finish writing to) the socket.
246
+
247
+ // There can be a race between the socket pool checking checking whether a
248
+ // socket is still connected, receiving the FIN, and sending/reading data
249
+ // on a reused socket. If we receive the FIN between the connectedness
250
+ // check and writing/reading from the socket, we may first learn the socket
251
+ // is disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most
252
+ // likely happen when trying to retrieve its IP address.
253
+ // See http://crbug.com/105824 for more details.
254
+
255
+ // We resend a request only if we reused a keep-alive connection and
256
+ // did not yet receive any header data. This automatically prevents an
257
+ // infinite resend loop because we'll run out of the cached keep-alive
258
+ // connections eventually.
259
+ continue
260
+ }
261
+ }
262
+ }
263
+ break
264
+ }
265
+ return resp , err
236
266
}
237
267
238
268
// RegisterProtocol registers a new protocol with scheme.
@@ -805,6 +835,7 @@ type persistConn struct {
805
835
numExpectedResponses int
806
836
closed bool // whether conn has been closed
807
837
broken bool // an error has happened on this connection; marked broken so it's not reused.
838
+ reused bool // whether conn has had successful request/response and is being reused.
808
839
// mutateHeaderFunc is an optional func to modify extra
809
840
// headers on each outbound request before it's written. (the
810
841
// original Request given to RoundTrip is not modified)
@@ -819,6 +850,22 @@ func (pc *persistConn) isBroken() bool {
819
850
return b
820
851
}
821
852
853
+ // isReused reports whether this connection is in a known broken state.
854
+ func (pc * persistConn ) isReused () bool {
855
+ pc .lk .Lock ()
856
+ r := pc .reused
857
+ pc .lk .Unlock ()
858
+ return r
859
+ }
860
+
861
+ // markReused marks this connection as having been successfully used for a request and response.
862
+ func (pc * persistConn ) markReused () bool {
863
+ pc .lk .Lock ()
864
+ pc .reused = true
865
+ pc .lk .Unlock ()
866
+ return true
867
+ }
868
+
822
869
func (pc * persistConn ) cancelRequest () {
823
870
pc .conn .Close ()
824
871
}
@@ -840,6 +887,9 @@ func (pc *persistConn) readLoop() {
840
887
841
888
for alive {
842
889
pb , err := pc .br .Peek (1 )
890
+ if err != nil {
891
+ err = beforeRespHeaderError {err }
892
+ }
843
893
844
894
pc .lk .Lock ()
845
895
if pc .numExpectedResponses == 0 {
@@ -910,13 +960,15 @@ func (pc *persistConn) readLoop() {
910
960
err == nil &&
911
961
! pc .sawEOF &&
912
962
pc .wroteRequest () &&
963
+ pc .markReused () &&
913
964
pc .t .putIdleConn (pc )
914
965
}
915
966
}
916
967
917
968
if alive && ! hasBody {
918
969
alive = ! pc .sawEOF &&
919
970
pc .wroteRequest () &&
971
+ pc .markReused () &&
920
972
pc .t .putIdleConn (pc )
921
973
}
922
974
@@ -1028,6 +1080,12 @@ func (e *httpError) Temporary() bool { return true }
1028
1080
var errTimeout error = & httpError {err : "net/http: timeout awaiting response headers" , timeout : true }
1029
1081
var errClosed error = & httpError {err : "net/http: transport closed before response was received" }
1030
1082
1083
+ // beforeRespHeaderError is used to indicate when an IO error has occurred before
1084
+ // any header data was received.
1085
+ type beforeRespHeaderError struct {
1086
+ error
1087
+ }
1088
+
1031
1089
func (pc * persistConn ) roundTrip (req * transportRequest ) (resp * Response , err error ) {
1032
1090
pc .t .setReqCanceler (req .Request , pc .cancelRequest )
1033
1091
pc .lk .Lock ()
@@ -1086,7 +1144,7 @@ WaitResponse:
1086
1144
select {
1087
1145
case err := <- writeErrCh :
1088
1146
if err != nil {
1089
- re = responseAndError {nil , err }
1147
+ re = responseAndError {nil , beforeRespHeaderError { err } }
1090
1148
pc .close ()
1091
1149
break WaitResponse
1092
1150
}
0 commit comments