1
0
mirror of https://github.com/golang/go synced 2024-09-29 22:34:33 -06:00

net/http: update bundled http2 copy

Updates golang.org/x/net/http2 to git rev 438097d76

Fixes #13444

Change-Id: I699ac02d23b56db3e8a27d3f599ae56cd0a5b4b2
Reviewed-on: https://go-review.googlesource.com/17570
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Brad Fitzpatrick 2015-12-08 21:42:52 +00:00
parent 616e45eaa1
commit 9b8080f37e

View File

@ -3858,6 +3858,7 @@ type http2clientStream struct {
inflow http2flow // guarded by cc.mu inflow http2flow // guarded by cc.mu
bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
readErr error // sticky read error; owned by transportResponseBody.Read readErr error // sticky read error; owned by transportResponseBody.Read
stopReqBody bool // stop writing req body; guarded by cc.mu
peerReset chan struct{} // closed on peer reset peerReset chan struct{} // closed on peer reset
resetErr error // populated before peerReset is closed resetErr error // populated before peerReset is closed
@ -3874,6 +3875,14 @@ func (cs *http2clientStream) checkReset() error {
} }
} }
func (cs *http2clientStream) abortRequestBodyWrite() {
cc := cs.cc
cc.mu.Lock()
cs.stopReqBody = true
cc.cond.Broadcast()
cc.mu.Unlock()
}
type http2stickyErrWriter struct { type http2stickyErrWriter struct {
w io.Writer w io.Writer
err *error err *error
@ -4202,26 +4211,25 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
return nil, werr return nil, werr
} }
var bodyCopyErrc chan error var bodyCopyErrc chan error // result of body copy
var gotResHeaders chan struct{} // closed on resheaders
if hasBody { if hasBody {
bodyCopyErrc = make(chan error, 1) bodyCopyErrc = make(chan error, 1)
gotResHeaders = make(chan struct{})
go func() { go func() {
bodyCopyErrc <- cs.writeRequestBody(req.Body, gotResHeaders) bodyCopyErrc <- cs.writeRequestBody(req.Body)
}() }()
} }
for { for {
select { select {
case re := <-cs.resc: case re := <-cs.resc:
if gotResHeaders != nil { res := re.res
close(gotResHeaders) if re.err != nil || res.StatusCode > 299 {
cs.abortRequestBodyWrite()
} }
if re.err != nil { if re.err != nil {
return nil, re.err return nil, re.err
} }
res := re.res
res.Request = req res.Request = req
res.TLS = cc.tlsState res.TLS = cc.tlsState
return res, nil return res, nil
@ -4233,45 +4241,49 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
} }
} }
var http2errServerResponseBeforeRequestBody = errors.New("http2: server sent response while still writing request body") // errAbortReqBodyWrite is an internal error value.
// It doesn't escape to callers.
var http2errAbortReqBodyWrite = errors.New("http2: aborting request body write")
func (cs *http2clientStream) writeRequestBody(body io.Reader, gotResHeaders <-chan struct{}) error { func (cs *http2clientStream) writeRequestBody(body io.ReadCloser) (err error) {
cc := cs.cc cc := cs.cc
sentEnd := false sentEnd := false
buf := cc.frameScratchBuffer() buf := cc.frameScratchBuffer()
defer cc.putFrameScratchBuffer(buf) defer cc.putFrameScratchBuffer(buf)
for !sentEnd { defer func() {
var sawEOF bool
n, err := io.ReadFull(body, buf) cerr := body.Close()
if err == io.ErrUnexpectedEOF { if err == nil {
err = cerr
}
}()
var sawEOF bool
for !sawEOF {
n, err := body.Read(buf)
if err == io.EOF {
sawEOF = true sawEOF = true
err = nil err = nil
} else if err == io.EOF {
break
} else if err != nil { } else if err != nil {
return err return err
} }
toWrite := buf[:n] remain := buf[:n]
for len(toWrite) > 0 && err == nil { for len(remain) > 0 && err == nil {
var allowed int32 var allowed int32
allowed, err = cs.awaitFlowControl(int32(len(toWrite))) allowed, err = cs.awaitFlowControl(len(remain))
if err != nil { if err != nil {
return err return err
} }
cc.wmu.Lock() cc.wmu.Lock()
select { data := remain[:allowed]
case <-gotResHeaders: remain = remain[allowed:]
err = http2errServerResponseBeforeRequestBody sentEnd = sawEOF && len(remain) == 0
case <-cs.peerReset: err = cc.fr.WriteData(cs.ID, sentEnd, data)
err = cs.resetErr if err == nil {
default:
data := toWrite[:allowed] err = cc.bw.Flush()
toWrite = toWrite[allowed:]
sentEnd = sawEOF && len(toWrite) == 0
err = cc.fr.WriteData(cs.ID, sentEnd, data)
} }
cc.wmu.Unlock() cc.wmu.Unlock()
} }
@ -4280,8 +4292,6 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, gotResHeaders <-ch
} }
} }
var err error
cc.wmu.Lock() cc.wmu.Lock()
if !sentEnd { if !sentEnd {
err = cc.fr.WriteData(cs.ID, true, nil) err = cc.fr.WriteData(cs.ID, true, nil)
@ -4298,7 +4308,7 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, gotResHeaders <-ch
// control tokens from the server. // control tokens from the server.
// It returns either the non-zero number of tokens taken or an error // It returns either the non-zero number of tokens taken or an error
// if the stream is dead. // if the stream is dead.
func (cs *http2clientStream) awaitFlowControl(maxBytes int32) (taken int32, err error) { func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
cc := cs.cc cc := cs.cc
cc.mu.Lock() cc.mu.Lock()
defer cc.mu.Unlock() defer cc.mu.Unlock()
@ -4306,13 +4316,17 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int32) (taken int32, err
if cc.closed { if cc.closed {
return 0, http2errClientConnClosed return 0, http2errClientConnClosed
} }
if cs.stopReqBody {
return 0, http2errAbortReqBodyWrite
}
if err := cs.checkReset(); err != nil { if err := cs.checkReset(); err != nil {
return 0, err return 0, err
} }
if a := cs.flow.available(); a > 0 { if a := cs.flow.available(); a > 0 {
take := a take := a
if take > maxBytes { if int(take) > maxBytes {
take = maxBytes
take = int32(maxBytes)
} }
if take > int32(cc.maxFrameSize) { if take > int32(cc.maxFrameSize) {
take = int32(cc.maxFrameSize) take = int32(cc.maxFrameSize)
@ -4751,6 +4765,7 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
cs.resetErr = err cs.resetErr = err
close(cs.peerReset) close(cs.peerReset)
cs.bufPipe.CloseWithError(err) cs.bufPipe.CloseWithError(err)
cs.cc.cond.Broadcast()
} }
delete(rl.activeRes, cs.ID) delete(rl.activeRes, cs.ID)
return nil return nil