|
@@ -543,35 +543,40 @@ var errServerResponseBeforeRequestBody = errors.New("http2: server sent response
|
|
|
func (cs *clientStream) writeRequestBody(body io.Reader, gotResHeaders <-chan struct{}) error {
|
|
func (cs *clientStream) writeRequestBody(body io.Reader, gotResHeaders <-chan struct{}) error {
|
|
|
cc := cs.cc
|
|
cc := cs.cc
|
|
|
done := false
|
|
done := false
|
|
|
- for !done {
|
|
|
|
|
- buf := cc.frameScratchBuffer()
|
|
|
|
|
-
|
|
|
|
|
- taken, err := cs.awaitFlowControl(int32(len(buf)))
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ buf := cc.frameScratchBuffer()
|
|
|
|
|
+ defer cc.putFrameScratchBuffer(buf)
|
|
|
|
|
|
|
|
- n, err := io.ReadFull(body, buf[:taken])
|
|
|
|
|
|
|
+ for !done {
|
|
|
|
|
+ n, err := io.ReadFull(body, buf)
|
|
|
if err == io.ErrUnexpectedEOF {
|
|
if err == io.ErrUnexpectedEOF {
|
|
|
done = true
|
|
done = true
|
|
|
|
|
+ err = nil
|
|
|
} else if err == io.EOF {
|
|
} else if err == io.EOF {
|
|
|
break
|
|
break
|
|
|
} else if err != nil {
|
|
} else if err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- cc.wmu.Lock()
|
|
|
|
|
- select {
|
|
|
|
|
- case <-gotResHeaders:
|
|
|
|
|
- err = errServerResponseBeforeRequestBody
|
|
|
|
|
- case <-cs.peerReset:
|
|
|
|
|
- err = cs.resetErr
|
|
|
|
|
- default:
|
|
|
|
|
- err = cc.fr.WriteData(cs.ID, done, buf[:n])
|
|
|
|
|
- }
|
|
|
|
|
- cc.wmu.Unlock()
|
|
|
|
|
- cc.putFrameScratchBuffer(buf)
|
|
|
|
|
|
|
+ toWrite := buf[:n]
|
|
|
|
|
+ for len(toWrite) > 0 && err == nil {
|
|
|
|
|
+ var allowed int32
|
|
|
|
|
+ allowed, err = cs.awaitFlowControl(int32(len(toWrite)))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ cc.wmu.Lock()
|
|
|
|
|
+ select {
|
|
|
|
|
+ case <-gotResHeaders:
|
|
|
|
|
+ err = errServerResponseBeforeRequestBody
|
|
|
|
|
+ case <-cs.peerReset:
|
|
|
|
|
+ err = cs.resetErr
|
|
|
|
|
+ default:
|
|
|
|
|
+ err = cc.fr.WriteData(cs.ID, done, toWrite[:allowed])
|
|
|
|
|
+ toWrite = toWrite[allowed:]
|
|
|
|
|
+ }
|
|
|
|
|
+ cc.wmu.Unlock()
|
|
|
|
|
+ }
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
@@ -591,10 +596,11 @@ func (cs *clientStream) writeRequestBody(body io.Reader, gotResHeaders <-chan st
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// awaitFlowControl waits for [1,max] flow 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 *clientStream) awaitFlowControl(max int32) (taken int32, err error) {
|
|
|
|
|
|
|
+// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow
|
|
|
|
|
+// 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 *clientStream) awaitFlowControl(maxBytes int32) (taken int32, err error) {
|
|
|
cc := cs.cc
|
|
cc := cs.cc
|
|
|
cc.mu.Lock()
|
|
cc.mu.Lock()
|
|
|
defer cc.mu.Unlock()
|
|
defer cc.mu.Unlock()
|
|
@@ -607,8 +613,11 @@ func (cs *clientStream) awaitFlowControl(max int32) (taken int32, err error) {
|
|
|
}
|
|
}
|
|
|
if a := cs.flow.available(); a > 0 {
|
|
if a := cs.flow.available(); a > 0 {
|
|
|
take := a
|
|
take := a
|
|
|
- if take > max {
|
|
|
|
|
- take = max
|
|
|
|
|
|
|
+ if take > maxBytes {
|
|
|
|
|
+ take = maxBytes
|
|
|
|
|
+ }
|
|
|
|
|
+ if take > int32(cc.maxFrameSize) {
|
|
|
|
|
+ take = int32(cc.maxFrameSize)
|
|
|
}
|
|
}
|
|
|
cs.flow.take(take)
|
|
cs.flow.take(take)
|
|
|
return take, nil
|
|
return take, nil
|