|
@@ -518,11 +518,14 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
|
func authorityAddr(scheme string, authority string) (addr string) {
|
|
|
host, port, err := net.SplitHostPort(authority)
|
|
|
if err != nil { // authority didn't have a port
|
|
|
+ host = authority
|
|
|
+ port = ""
|
|
|
+ }
|
|
|
+ if port == "" { // authority's port was empty
|
|
|
port = "443"
|
|
|
if scheme == "http" {
|
|
|
port = "80"
|
|
|
}
|
|
|
- host = authority
|
|
|
}
|
|
|
if a, err := idna.ToASCII(host); err == nil {
|
|
|
host = a
|
|
@@ -1268,21 +1271,23 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
|
|
|
|
cancelRequest := func(cs *clientStream, err error) error {
|
|
|
cs.cc.mu.Lock()
|
|
|
- defer cs.cc.mu.Unlock()
|
|
|
- cs.abortStreamLocked(err)
|
|
|
- if cs.ID != 0 {
|
|
|
- // This request may have failed because of a problem with the connection,
|
|
|
- // or for some unrelated reason. (For example, the user might have canceled
|
|
|
- // the request without waiting for a response.) Mark the connection as
|
|
|
- // not reusable, since trying to reuse a dead connection is worse than
|
|
|
- // unnecessarily creating a new one.
|
|
|
- //
|
|
|
- // If cs.ID is 0, then the request was never allocated a stream ID and
|
|
|
- // whatever went wrong was unrelated to the connection. We might have
|
|
|
- // timed out waiting for a stream slot when StrictMaxConcurrentStreams
|
|
|
- // is set, for example, in which case retrying on a different connection
|
|
|
- // will not help.
|
|
|
- cs.cc.doNotReuse = true
|
|
|
+ bodyClosed := cs.reqBodyClosed
|
|
|
+ cs.cc.mu.Unlock()
|
|
|
+ // Wait for the request body to be closed.
|
|
|
+ //
|
|
|
+ // If nothing closed the body before now, abortStreamLocked
|
|
|
+ // will have started a goroutine to close it.
|
|
|
+ //
|
|
|
+ // Closing the body before returning avoids a race condition
|
|
|
+ // with net/http checking its readTrackingBody to see if the
|
|
|
+ // body was read from or closed. See golang/go#60041.
|
|
|
+ //
|
|
|
+ // The body is closed in a separate goroutine without the
|
|
|
+ // connection mutex held, but dropping the mutex before waiting
|
|
|
+ // will keep us from holding it indefinitely if the body
|
|
|
+ // close is slow for some reason.
|
|
|
+ if bodyClosed != nil {
|
|
|
+ <-bodyClosed
|
|
|
}
|
|
|
return err
|
|
|
}
|
|
@@ -1301,11 +1306,14 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
|
return handleResponseHeaders()
|
|
|
default:
|
|
|
waitDone()
|
|
|
- return nil, cancelRequest(cs, cs.abortErr)
|
|
|
+ return nil, cs.abortErr
|
|
|
}
|
|
|
case <-ctx.Done():
|
|
|
- return nil, cancelRequest(cs, ctx.Err())
|
|
|
+ err := ctx.Err()
|
|
|
+ cs.abortStream(err)
|
|
|
+ return nil, cancelRequest(cs, err)
|
|
|
case <-cs.reqCancel:
|
|
|
+ cs.abortStream(errRequestCanceled)
|
|
|
return nil, cancelRequest(cs, errRequestCanceled)
|
|
|
}
|
|
|
}
|
|
@@ -1863,6 +1871,9 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
+ if !httpguts.ValidHostHeader(host) {
|
|
|
+ return nil, errors.New("http2: invalid Host header")
|
|
|
+ }
|
|
|
|
|
|
var path string
|
|
|
if req.Method != "CONNECT" {
|
|
@@ -1899,7 +1910,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|
|
// 8.1.2.3 Request Pseudo-Header Fields
|
|
|
// The :path pseudo-header field includes the path and query parts of the
|
|
|
// target URI (the path-absolute production and optionally a '?' character
|
|
|
- // followed by the query production (see Sections 3.3 and 3.4 of
|
|
|
+ // followed by the query production, see Sections 3.3 and 3.4 of
|
|
|
// [RFC3986]).
|
|
|
f(":authority", host)
|
|
|
m := req.Method
|