1
0
mirror of https://github.com/golang/go synced 2024-09-29 20:24:34 -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
bytesRemain int64 // -1 means unknown; 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
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 {
w io.Writer
err *error
@ -4202,26 +4211,25 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
return nil, werr
}
var bodyCopyErrc chan error
var gotResHeaders chan struct{} // closed on resheaders
var bodyCopyErrc chan error // result of body copy
if hasBody {
bodyCopyErrc = make(chan error, 1)
gotResHeaders = make(chan struct{})
go func() {
bodyCopyErrc <- cs.writeRequestBody(req.Body, gotResHeaders)
bodyCopyErrc <- cs.writeRequestBody(req.Body)
}()
}
for {
select {
case re := <-cs.resc:
if gotResHeaders != nil {
close(gotResHeaders)
res := re.res
if re.err != nil || res.StatusCode > 299 {
cs.abortRequestBodyWrite()
}
if re.err != nil {
return nil, re.err
}
res := re.res
res.Request = req
res.TLS = cc.tlsState
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
sentEnd := false
buf := cc.frameScratchBuffer()
defer cc.putFrameScratchBuffer(buf)
for !sentEnd {
var sawEOF bool
n, err := io.ReadFull(body, buf)
if err == io.ErrUnexpectedEOF {
defer func() {
cerr := body.Close()
if err == nil {
err = cerr
}
}()
var sawEOF bool
for !sawEOF {
n, err := body.Read(buf)
if err == io.EOF {
sawEOF = true
err = nil
} else if err == io.EOF {
break
} else if err != nil {
return err
}
toWrite := buf[:n]
for len(toWrite) > 0 && err == nil {
remain := buf[:n]
for len(remain) > 0 && err == nil {
var allowed int32
allowed, err = cs.awaitFlowControl(int32(len(toWrite)))
allowed, err = cs.awaitFlowControl(len(remain))
if err != nil {
return err
}
cc.wmu.Lock()
select {
case <-gotResHeaders:
err = http2errServerResponseBeforeRequestBody
case <-cs.peerReset:
err = cs.resetErr
default:
data := toWrite[:allowed]
toWrite = toWrite[allowed:]
sentEnd = sawEOF && len(toWrite) == 0
err = cc.fr.WriteData(cs.ID, sentEnd, data)
data := remain[:allowed]
remain = remain[allowed:]
sentEnd = sawEOF && len(remain) == 0
err = cc.fr.WriteData(cs.ID, sentEnd, data)
if err == nil {
err = cc.bw.Flush()
}
cc.wmu.Unlock()
}
@ -4280,8 +4292,6 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, gotResHeaders <-ch
}
}
var err error
cc.wmu.Lock()
if !sentEnd {
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.
// It returns either the non-zero number of tokens taken or an error
// 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.mu.Lock()
defer cc.mu.Unlock()
@ -4306,13 +4316,17 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int32) (taken int32, err
if cc.closed {
return 0, http2errClientConnClosed
}
if cs.stopReqBody {
return 0, http2errAbortReqBodyWrite
}
if err := cs.checkReset(); err != nil {
return 0, err
}
if a := cs.flow.available(); a > 0 {
take := a
if take > maxBytes {
take = maxBytes
if int(take) > maxBytes {
take = int32(maxBytes)
}
if take > int32(cc.maxFrameSize) {
take = int32(cc.maxFrameSize)
@ -4751,6 +4765,7 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
cs.resetErr = err
close(cs.peerReset)
cs.bufPipe.CloseWithError(err)
cs.cc.cond.Broadcast()
}
delete(rl.activeRes, cs.ID)
return nil