http2: change the pipe and buffer code
Make the pipe code take an interface as the backing store. Now a pipe
is something that's goroutine-safe and does the Cond waits but its underlying data
is now an interface: anything that's a ReaderWriter with a Len method (such as a
*bytes.Buffer), or a fixedBuffer (renamed in this CL from 'buffer').
This opens the ground to having a non-fixed buffer used with pipe.
This also moves the CloseWithError code up into the pipe code, out of
fixedBuffer.
Change-Id: Ia3b853e8aa8920807b705ff4e41bed934a8c67b7
Reviewed-on: https://go-review.googlesource.com/16312
Reviewed-by: Blake Mizerany <blake.mizerany@gmail.com>
diff --git a/http2/server.go b/http2/server.go
index ba408fe..5fb92cd 100644
--- a/http2/server.go
+++ b/http2/server.go
@@ -65,6 +65,7 @@
var (
errClientDisconnected = errors.New("client disconnected")
errClosedBody = errors.New("body closed by handler")
+ errHandlerComplete = errors.New("http2: request body closed due to handler exiting")
errStreamClosed = errors.New("http2: stream closed")
)
@@ -872,7 +873,7 @@
errCancel := StreamError{st.id, ErrCodeCancel}
sc.resetStream(errCancel)
case stateHalfClosedRemote:
- sc.closeStream(st, nil)
+ sc.closeStream(st, errHandlerComplete)
}
}
@@ -1142,7 +1143,7 @@
}
delete(sc.streams, st.id)
if p := st.body; p != nil {
- p.Close(err)
+ p.CloseWithError(err)
}
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
sc.writeSched.forgetStream(st.id)
@@ -1246,7 +1247,7 @@
// Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
- st.body.Close(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
+ st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
return StreamError{id, ErrCodeStreamClosed}
}
if len(data) > 0 {
@@ -1266,10 +1267,10 @@
}
if f.StreamEnded() {
if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
- st.body.Close(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
+ st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
st.declBodyBytes, st.bodyBytes))
} else {
- st.body.Close(io.EOF)
+ st.body.CloseWithError(io.EOF)
}
st.state = stateHalfClosedRemote
}
@@ -1493,9 +1494,8 @@
}
if bodyOpen {
body.pipe = &pipe{
- b: buffer{buf: make([]byte, initialWindowSize)}, // TODO: share/remove XXX
+ b: &fixedBuffer{buf: make([]byte, initialWindowSize)}, // TODO: share/remove XXX
}
- body.pipe.c.L = &body.pipe.m
if vv, ok := rp.header["Content-Length"]; ok {
req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
@@ -1655,7 +1655,7 @@
func (b *requestBody) Close() error {
if b.pipe != nil {
- b.pipe.Close(errClosedBody)
+ b.pipe.CloseWithError(errClosedBody)
}
b.closed = true
return nil