Commit bf5e19fb authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: tolerate old buggy user agents, per RFC 2616 section 4.1

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/11491Reviewed-by: 's avatarAndrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
parent fe1cecfa
......@@ -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()
......
......@@ -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
......@@ -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 {
......@@ -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
......@@ -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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment