Skip to content

Commit 743f818

Browse files
bradfitzrsc
authored andcommitted
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
1 parent 93ea2ae commit 743f818

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

src/pkg/http/request.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,8 @@ func (r *Request) FormValue(key string) string {
635635
}
636636
return ""
637637
}
638+
639+
func (r *Request) expectsContinue() bool {
640+
expectation, ok := r.Header["Expect"]
641+
return ok && strings.ToLower(expectation) == "100-continue"
642+
}

src/pkg/http/server.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type Conn struct {
5656
closeAfterReply bool // close connection after this reply
5757
chunking bool // using chunked transfer encoding for reply body
5858
wroteHeader bool // reply header has been written
59+
wroteContinue bool // 100 Continue response was written
5960
header map[string]string // reply header parameters
6061
written int64 // number of bytes written in body
6162
status int // status code passed to WriteHeader
@@ -75,6 +76,28 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
7576
return c, nil
7677
}
7778

79+
// wrapper around io.ReaderCloser which on first read, sends an
80+
// HTTP/1.1 100 Continue header
81+
type expectContinueReader struct {
82+
conn *Conn
83+
readCloser io.ReadCloser
84+
}
85+
86+
func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
87+
if !ecr.conn.wroteContinue && !ecr.conn.hijacked {
88+
ecr.conn.wroteContinue = true
89+
if ecr.conn.Req.ProtoAtLeast(1, 1) {
90+
io.WriteString(ecr.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
91+
ecr.conn.buf.Flush()
92+
}
93+
}
94+
return ecr.readCloser.Read(p)
95+
}
96+
97+
func (ecr *expectContinueReader) Close() os.Error {
98+
return ecr.readCloser.Close()
99+
}
100+
78101
// Read next request from connection.
79102
func (c *Conn) readRequest() (req *Request, err os.Error) {
80103
if c.hijacked {
@@ -87,8 +110,15 @@ func (c *Conn) readRequest() (req *Request, err os.Error) {
87110
// Reset per-request connection state.
88111
c.header = make(map[string]string)
89112
c.wroteHeader = false
113+
c.wroteContinue = false
90114
c.Req = req
91115

116+
// Expect 100 Continue support
117+
if req.expectsContinue() {
118+
// Wrap the Body reader with one that replies on the connection
119+
req.Body = &expectContinueReader{readCloser: req.Body, conn: c}
120+
}
121+
92122
// Default output is HTML encoded in UTF-8.
93123
c.SetHeader("Content-Type", "text/html; charset=utf-8")
94124

0 commit comments

Comments
 (0)