]> Cypherpunks repositories - gostls13.git/commitdiff
http: reply to Expect 100-continue requests automatically
authorBrad Fitzpatrick <brad@danga.com>
Wed, 16 Jun 2010 17:15:39 +0000 (10:15 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 16 Jun 2010 17:15:39 +0000 (10:15 -0700)
This CL replaces my earlier https://golang.org/cl/1640044/show
in which Continue handling was explicit.  Instead, this CL makes
it automatic.  Reading from Body() is an implicit acknowledgement
that the request headers were fine and the body is wanted.  In that
case, the 100 Continue response is written automatically when the
request continues the "Expect: 100-continue" header.

R=rsc, adg
CC=golang-dev
https://golang.org/cl/1610042

src/pkg/http/request.go
src/pkg/http/server.go

index c01b2dd26ea53e01be367ca0d3daeea601376601..b1aface466acefd4a327835eda0ecbb318b705c6 100644 (file)
@@ -635,3 +635,8 @@ func (r *Request) FormValue(key string) string {
        }
        return ""
 }
+
+func (r *Request) expectsContinue() bool {
+       expectation, ok := r.Header["Expect"]
+       return ok && strings.ToLower(expectation) == "100-continue"
+}
index 9f0bc660878750a3605135e383244edbfd93d356..81ce98229ac843ab243fc2c14347b3e6d034ef57 100644 (file)
@@ -56,6 +56,7 @@ type Conn struct {
        closeAfterReply bool              // close connection after this reply
        chunking        bool              // using chunked transfer encoding for reply body
        wroteHeader     bool              // reply header has been written
+       wroteContinue   bool              // 100 Continue response was written
        header          map[string]string // reply header parameters
        written         int64             // number of bytes written in body
        status          int               // status code passed to WriteHeader
@@ -75,6 +76,28 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
        return c, nil
 }
 
+// wrapper around io.ReaderCloser which on first read, sends an
+// HTTP/1.1 100 Continue header
+type expectContinueReader struct {
+       conn       *Conn
+       readCloser io.ReadCloser
+}
+
+func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+       if !ecr.conn.wroteContinue && !ecr.conn.hijacked {
+               ecr.conn.wroteContinue = true
+               if ecr.conn.Req.ProtoAtLeast(1, 1) {
+                       io.WriteString(ecr.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+                       ecr.conn.buf.Flush()
+               }
+       }
+       return ecr.readCloser.Read(p)
+}
+
+func (ecr *expectContinueReader) Close() os.Error {
+       return ecr.readCloser.Close()
+}
+
 // Read next request from connection.
 func (c *Conn) readRequest() (req *Request, err os.Error) {
        if c.hijacked {
@@ -87,8 +110,15 @@ func (c *Conn) readRequest() (req *Request, err os.Error) {
        // Reset per-request connection state.
        c.header = make(map[string]string)
        c.wroteHeader = false
+       c.wroteContinue = false
        c.Req = req
 
+       // Expect 100 Continue support
+       if req.expectsContinue() {
+               // Wrap the Body reader with one that replies on the connection
+               req.Body = &expectContinueReader{readCloser: req.Body, conn: c}
+       }
+
        // Default output is HTML encoded in UTF-8.
        c.SetHeader("Content-Type", "text/html; charset=utf-8")