aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <brad@danga.com>2010-06-16 10:15:39 -0700
committerRuss Cox <rsc@golang.org>2010-06-16 10:15:39 -0700
commit743f818218c92822ee56d35e816d86a2205ff17a (patch)
treedd30ceea23ae9db64114f72d2547ea1ee077ddae
parent93ea2ae362d77b127c7f8235621e1adb4776efa1 (diff)
downloadgo-743f818218c92822ee56d35e816d86a2205ff17a.tar.gz
go-743f818218c92822ee56d35e816d86a2205ff17a.zip
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
-rw-r--r--src/pkg/http/request.go5
-rw-r--r--src/pkg/http/server.go30
2 files changed, 35 insertions, 0 deletions
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index c01b2dd26e..b1aface466 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -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"
+}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 9f0bc66087..81ce98229a 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -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")