1
0
mirror of https://github.com/golang/go synced 2024-11-21 18:54:43 -07:00

http: reply to Expect 100-continue requests automatically

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
This commit is contained in:
Brad Fitzpatrick 2010-06-16 10:15:39 -07:00 committed by Russ Cox
parent 93ea2ae362
commit 743f818218
2 changed files with 35 additions and 0 deletions

View File

@ -635,3 +635,8 @@ func (r *Request) FormValue(key string) string {
} }
return "" return ""
} }
func (r *Request) expectsContinue() bool {
expectation, ok := r.Header["Expect"]
return ok && strings.ToLower(expectation) == "100-continue"
}

View File

@ -56,6 +56,7 @@ type Conn struct {
closeAfterReply bool // close connection after this reply closeAfterReply bool // close connection after this reply
chunking bool // using chunked transfer encoding for reply body chunking bool // using chunked transfer encoding for reply body
wroteHeader bool // reply header has been written wroteHeader bool // reply header has been written
wroteContinue bool // 100 Continue response was written
header map[string]string // reply header parameters header map[string]string // reply header parameters
written int64 // number of bytes written in body written int64 // number of bytes written in body
status int // status code passed to WriteHeader 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 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. // Read next request from connection.
func (c *Conn) readRequest() (req *Request, err os.Error) { func (c *Conn) readRequest() (req *Request, err os.Error) {
if c.hijacked { if c.hijacked {
@ -87,8 +110,15 @@ func (c *Conn) readRequest() (req *Request, err os.Error) {
// Reset per-request connection state. // Reset per-request connection state.
c.header = make(map[string]string) c.header = make(map[string]string)
c.wroteHeader = false c.wroteHeader = false
c.wroteContinue = false
c.Req = req 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. // Default output is HTML encoded in UTF-8.
c.SetHeader("Content-Type", "text/html; charset=utf-8") c.SetHeader("Content-Type", "text/html; charset=utf-8")