Automatic 100-continue support
diff --git a/server.go b/server.go
index 51f8035..af49696 100644
--- a/server.go
+++ b/server.go
@@ -31,8 +31,6 @@
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
)
-// TODO: automatic 100-continue
-
// TODO: finish GOAWAY support. Consider each incoming frame type and
// whether it should be ignored during a shutdown race.
@@ -817,10 +815,15 @@
if authority == "" {
authority = rp.header.Get("Host")
}
+ needsContinue := rp.header.Get("Expect") == "100-continue"
+ if needsContinue {
+ rp.header.Del("Expect")
+ }
bodyOpen := rp.stream.state == stateOpen
body := &requestBody{
- sc: sc,
- streamID: rp.stream.id,
+ sc: sc,
+ streamID: rp.stream.id,
+ needsContinue: needsContinue,
}
url, err := url.ParseRequestURI(rp.path)
if err != nil {
@@ -969,6 +972,30 @@
})
}
+// called from handler goroutines.
+// h may be nil.
+func (sc *serverConn) write100ContinueHeaders(streamID uint32) {
+ sc.serveG.checkNotOn()
+ sc.writeFrame(frameWriteMsg{
+ write: (*serverConn).write100ContinueHeadersFrame,
+ v: &streamID,
+ streamID: streamID,
+ })
+}
+
+func (sc *serverConn) write100ContinueHeadersFrame(v interface{}) error {
+ sc.writeG.check()
+ streamID := *(v.(*uint32))
+ sc.headerWriteBuf.Reset()
+ sc.hpackEncoder.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
+ return sc.framer.WriteHeaders(HeadersFrameParam{
+ StreamID: streamID,
+ BlockFragment: sc.headerWriteBuf.Bytes(),
+ EndStream: false,
+ EndHeaders: true,
+ })
+}
+
func (sc *serverConn) writeDataFrame(v interface{}) error {
sc.writeG.check()
rws := v.(*responseWriterState)
@@ -1013,10 +1040,11 @@
}
type requestBody struct {
- sc *serverConn
- streamID uint32
- closed bool
- pipe *pipe // non-nil if we have a HTTP entity message body
+ sc *serverConn
+ streamID uint32
+ closed bool
+ pipe *pipe // non-nil if we have a HTTP entity message body
+ needsContinue bool // need to send a 100-continue
}
var errClosedBody = errors.New("body closed by handler")
@@ -1030,6 +1058,10 @@
}
func (b *requestBody) Read(p []byte) (n int, err error) {
+ if b.needsContinue {
+ b.needsContinue = false
+ b.sc.write100ContinueHeaders(b.streamID)
+ }
if b.pipe == nil {
return 0, io.EOF
}
@@ -1073,7 +1105,6 @@
snapHeader http.Header // snapshot of handlerHeader at WriteHeader time
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
status int // status code passed to WriteHeader
- wroteContinue bool // 100 Continue response was written
sentHeader bool // have we sent the header frame?
handlerDone bool // handler has finished