vendor: revendor for gRPC
This commit is contained in:
159
vendor/golang.org/x/net/http2/transport.go
generated
vendored
159
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@@ -139,9 +139,10 @@ func (t *Transport) initConnPool() {
|
||||
// ClientConn is the state of a single HTTP/2 client connection to an
|
||||
// HTTP/2 server.
|
||||
type ClientConn struct {
|
||||
t *Transport
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tlsState *tls.ConnectionState // nil only for specialized impls
|
||||
t *Transport
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tlsState *tls.ConnectionState // nil only for specialized impls
|
||||
singleUse bool // whether being used for a single http.Request
|
||||
|
||||
// readLoop goroutine fields:
|
||||
readerDone chan struct{} // closed on error
|
||||
@@ -153,6 +154,7 @@ type ClientConn struct {
|
||||
inflow flow // peer's conn-level flow control
|
||||
closed bool
|
||||
goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received
|
||||
goAwayDebug string // goAway frame's debug data, retained as a string
|
||||
streams map[uint32]*clientStream // client-initiated
|
||||
nextStreamID uint32
|
||||
bw *bufio.Writer
|
||||
@@ -337,7 +339,7 @@ func shouldRetryRequest(req *http.Request, err error) bool {
|
||||
return err == errClientConnUnusable
|
||||
}
|
||||
|
||||
func (t *Transport) dialClientConn(addr string) (*ClientConn, error) {
|
||||
func (t *Transport) dialClientConn(addr string, singleUse bool) (*ClientConn, error) {
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -346,7 +348,7 @@ func (t *Transport) dialClientConn(addr string) (*ClientConn, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.NewClientConn(tconn)
|
||||
return t.newClientConn(tconn, singleUse)
|
||||
}
|
||||
|
||||
func (t *Transport) newTLSConfig(host string) *tls.Config {
|
||||
@@ -407,6 +409,10 @@ func (t *Transport) expectContinueTimeout() time.Duration {
|
||||
}
|
||||
|
||||
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
return t.newClientConn(c, false)
|
||||
}
|
||||
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
|
||||
if VerboseLogs {
|
||||
t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
|
||||
}
|
||||
@@ -424,6 +430,7 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
initialWindowSize: 65535, // spec default
|
||||
maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
|
||||
streams: make(map[uint32]*clientStream),
|
||||
singleUse: singleUse,
|
||||
}
|
||||
cc.cond = sync.NewCond(&cc.mu)
|
||||
cc.flow.add(int32(initialWindowSize))
|
||||
@@ -494,7 +501,17 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
func (cc *ClientConn) setGoAway(f *GoAwayFrame) {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
|
||||
old := cc.goAway
|
||||
cc.goAway = f
|
||||
|
||||
// Merge the previous and current GoAway error frames.
|
||||
if cc.goAwayDebug == "" {
|
||||
cc.goAwayDebug = string(f.DebugData())
|
||||
}
|
||||
if old != nil && old.ErrCode != ErrCodeNo {
|
||||
cc.goAway.ErrCode = old.ErrCode
|
||||
}
|
||||
}
|
||||
|
||||
func (cc *ClientConn) CanTakeNewRequest() bool {
|
||||
@@ -504,6 +521,9 @@ func (cc *ClientConn) CanTakeNewRequest() bool {
|
||||
}
|
||||
|
||||
func (cc *ClientConn) canTakeNewRequestLocked() bool {
|
||||
if cc.singleUse && cc.nextStreamID > 1 {
|
||||
return false
|
||||
}
|
||||
return cc.goAway == nil && !cc.closed &&
|
||||
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
|
||||
cc.nextStreamID < 2147483647
|
||||
@@ -732,30 +752,34 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
bodyWritten := false
|
||||
ctx := reqContext(req)
|
||||
|
||||
handleReadLoopResponse := func(re resAndError) (*http.Response, error) {
|
||||
res := re.res
|
||||
if re.err != nil || res.StatusCode > 299 {
|
||||
// On error or status code 3xx, 4xx, 5xx, etc abort any
|
||||
// ongoing write, assuming that the server doesn't care
|
||||
// about our request body. If the server replied with 1xx or
|
||||
// 2xx, however, then assume the server DOES potentially
|
||||
// want our body (e.g. full-duplex streaming:
|
||||
// golang.org/issue/13444). If it turns out the server
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// we can keep it.
|
||||
bodyWriter.cancel()
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
}
|
||||
if re.err != nil {
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, re.err
|
||||
}
|
||||
res.Request = req
|
||||
res.TLS = cc.tlsState
|
||||
return res, nil
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case re := <-readLoopResCh:
|
||||
res := re.res
|
||||
if re.err != nil || res.StatusCode > 299 {
|
||||
// On error or status code 3xx, 4xx, 5xx, etc abort any
|
||||
// ongoing write, assuming that the server doesn't care
|
||||
// about our request body. If the server replied with 1xx or
|
||||
// 2xx, however, then assume the server DOES potentially
|
||||
// want our body (e.g. full-duplex streaming:
|
||||
// golang.org/issue/13444). If it turns out the server
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// we can keep it.
|
||||
bodyWriter.cancel()
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
}
|
||||
if re.err != nil {
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, re.err
|
||||
}
|
||||
res.Request = req
|
||||
res.TLS = cc.tlsState
|
||||
return res, nil
|
||||
return handleReadLoopResponse(re)
|
||||
case <-respHeaderTimer:
|
||||
cc.forgetStreamID(cs.ID)
|
||||
if !hasBody || bodyWritten {
|
||||
@@ -789,6 +813,12 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// forgetStreamID.
|
||||
return nil, cs.resetErr
|
||||
case err := <-bodyWriter.resc:
|
||||
// Prefer the read loop's response, if available. Issue 16102.
|
||||
select {
|
||||
case re := <-readLoopResCh:
|
||||
return handleReadLoopResponse(re)
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1160,6 +1190,19 @@ func (cc *ClientConn) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// GoAwayError is returned by the Transport when the server closes the
|
||||
// TCP connection after sending a GOAWAY frame.
|
||||
type GoAwayError struct {
|
||||
LastStreamID uint32
|
||||
ErrCode ErrCode
|
||||
DebugData string
|
||||
}
|
||||
|
||||
func (e GoAwayError) Error() string {
|
||||
return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
|
||||
e.LastStreamID, e.ErrCode, e.DebugData)
|
||||
}
|
||||
|
||||
func (rl *clientConnReadLoop) cleanup() {
|
||||
cc := rl.cc
|
||||
defer cc.tconn.Close()
|
||||
@@ -1170,10 +1213,18 @@ func (rl *clientConnReadLoop) cleanup() {
|
||||
// TODO: also do this if we've written the headers but not
|
||||
// gotten a response yet.
|
||||
err := cc.readerErr
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
cc.mu.Lock()
|
||||
if err == io.EOF {
|
||||
if cc.goAway != nil {
|
||||
err = GoAwayError{
|
||||
LastStreamID: cc.goAway.LastStreamID,
|
||||
ErrCode: cc.goAway.ErrCode,
|
||||
DebugData: cc.goAwayDebug,
|
||||
}
|
||||
} else {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
for _, cs := range rl.activeRes {
|
||||
cs.bufPipe.CloseWithError(err)
|
||||
}
|
||||
@@ -1191,7 +1242,7 @@ func (rl *clientConnReadLoop) cleanup() {
|
||||
|
||||
func (rl *clientConnReadLoop) run() error {
|
||||
cc := rl.cc
|
||||
rl.closeWhenIdle = cc.t.disableKeepAlives()
|
||||
rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
|
||||
gotReply := false // ever saw a reply
|
||||
for {
|
||||
f, err := cc.fr.ReadFrame()
|
||||
@@ -1486,10 +1537,27 @@ var errClosedResponseBody = errors.New("http2: response body closed")
|
||||
|
||||
func (b transportResponseBody) Close() error {
|
||||
cs := b.cs
|
||||
if cs.bufPipe.Err() != io.EOF {
|
||||
// TODO: write test for this
|
||||
cs.cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
|
||||
cc := cs.cc
|
||||
|
||||
serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
|
||||
unread := cs.bufPipe.Len()
|
||||
|
||||
if unread > 0 || !serverSentStreamEnd {
|
||||
cc.mu.Lock()
|
||||
cc.wmu.Lock()
|
||||
if !serverSentStreamEnd {
|
||||
cc.fr.WriteRSTStream(cs.ID, ErrCodeCancel)
|
||||
}
|
||||
// Return connection-level flow control.
|
||||
if unread > 0 {
|
||||
cc.inflow.add(int32(unread))
|
||||
cc.fr.WriteWindowUpdate(0, uint32(unread))
|
||||
}
|
||||
cc.bw.Flush()
|
||||
cc.wmu.Unlock()
|
||||
cc.mu.Unlock()
|
||||
}
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
return nil
|
||||
}
|
||||
@@ -1497,6 +1565,7 @@ func (b transportResponseBody) Close() error {
|
||||
func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
||||
cc := rl.cc
|
||||
cs := cc.streamByID(f.StreamID, f.StreamEnded())
|
||||
data := f.Data()
|
||||
if cs == nil {
|
||||
cc.mu.Lock()
|
||||
neverSent := cc.nextStreamID
|
||||
@@ -1510,9 +1579,17 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
||||
// TODO: be stricter here? only silently ignore things which
|
||||
// we canceled, but not things which were closed normally
|
||||
// by the peer? Tough without accumulating too much state.
|
||||
|
||||
// But at least return their flow control:
|
||||
if len(data) > 0 {
|
||||
cc.wmu.Lock()
|
||||
cc.fr.WriteWindowUpdate(0, uint32(len(data)))
|
||||
cc.bw.Flush()
|
||||
cc.wmu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if data := f.Data(); len(data) > 0 {
|
||||
if len(data) > 0 {
|
||||
if cs.bufPipe.b == nil {
|
||||
// Data frame after it's already closed?
|
||||
cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
|
||||
@@ -1557,7 +1634,7 @@ func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
|
||||
}
|
||||
cs.bufPipe.closeWithErrorAndCode(err, code)
|
||||
delete(rl.activeRes, cs.ID)
|
||||
if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
|
||||
if isConnectionCloseRequest(cs.req) {
|
||||
rl.closeWhenIdle = true
|
||||
}
|
||||
}
|
||||
@@ -1679,8 +1756,10 @@ func (rl *clientConnReadLoop) processPushPromise(f *PushPromiseFrame) error {
|
||||
}
|
||||
|
||||
func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, err error) {
|
||||
// TODO: do something with err? send it as a debug frame to the peer?
|
||||
// But that's only in GOAWAY. Invent a new frame type? Is there one already?
|
||||
// TODO: map err to more interesting error codes, once the
|
||||
// HTTP community comes up with some. But currently for
|
||||
// RST_STREAM there's no equivalent to GOAWAY frame's debug
|
||||
// data, and the error codes are all pretty vague ("cancel").
|
||||
cc.wmu.Lock()
|
||||
cc.fr.WriteRSTStream(streamID, code)
|
||||
cc.bw.Flush()
|
||||
@@ -1830,3 +1909,9 @@ func (s bodyWriterState) scheduleBodyWrite() {
|
||||
s.timer.Reset(s.delay)
|
||||
}
|
||||
}
|
||||
|
||||
// isConnectionCloseRequest reports whether req should use its own
|
||||
// connection for a single request and then close the connection.
|
||||
func isConnectionCloseRequest(req *http.Request) bool {
|
||||
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
}
|
||||
|
Reference in New Issue
Block a user