Skip to content

Commit

Permalink
net/http: tolerate old buggy user agents, per RFC 2616 section 4.1
Browse files Browse the repository at this point in the history
Some old buggy browsers sent extra CRLF(s) after POST bodies. Skip
over them before reading subsequent requests.

Fixes #10876

Change-Id: I62eacf2b3e985caffa85aee3de39d8cd3548130b
Reviewed-on: https://go-review.googlesource.com/11491
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information
bradfitz committed Jun 25, 2015
1 parent fe1cecf commit bf5e19f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/net/http/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2963,6 +2963,30 @@ func TestNoContentLengthIfTransferEncoding(t *testing.T) {
}
}

// tolerate extra CRLF(s) before Request-Line on subsequent requests on a conn
// Issue 10876.
func TestTolerateCRLFBeforeRequestLine(t *testing.T) {
req := []byte("POST / HTTP/1.1\r\nHost: golang.org\r\nContent-Length: 3\r\n\r\nABC" +
"\r\n\r\n" + // <-- this stuff is bogus, but we'll ignore it
"GET / HTTP/1.1\r\nHost: golang.org\r\n\r\n")
var buf bytes.Buffer
conn := &rwTestConn{
Reader: bytes.NewReader(req),
Writer: &buf,
closec: make(chan bool, 1),
}
ln := &oneConnListener{conn: conn}
numReq := 0
go Serve(ln, HandlerFunc(func(rw ResponseWriter, r *Request) {
numReq++
}))
<-conn.closec
if numReq != 2 {
t.Errorf("num requests = %d; want 2", numReq)
t.Logf("Res: %s", buf.Bytes())
}
}

func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
Expand Down
19 changes: 19 additions & 0 deletions src/net/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type conn struct {
lr *io.LimitedReader // io.LimitReader(sr)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
tlsState *tls.ConnectionState // or nil when not using TLS
lastMethod string // method of previous request, or ""

mu sync.Mutex // guards the following
clientGone bool // if client has disconnected mid-request
Expand Down Expand Up @@ -618,6 +619,11 @@ func (c *conn) readRequest() (w *response, err error) {
}

c.lr.N = c.server.initialLimitedReaderSize()
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below
c.buf.Reader.Discard(numLeadingCRorLF(peek))
}
var req *Request
if req, err = ReadRequest(c.buf.Reader); err != nil {
if c.lr.N == 0 {
Expand All @@ -626,6 +632,7 @@ func (c *conn) readRequest() (w *response, err error) {
return nil, err
}
c.lr.N = noLimit
c.lastMethod = req.Method

req.RemoteAddr = c.remoteAddr
req.TLS = c.tlsState
Expand Down Expand Up @@ -2181,3 +2188,15 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
}
return
}

func numLeadingCRorLF(v []byte) (n int) {
for _, b := range v {
if b == '\r' || b == '\n' {
n++
continue
}
break
}
return

}

0 comments on commit bf5e19f

Please sign in to comment.