]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: tolerate old buggy user agents, per RFC 2616 section 4.1
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 25 Jun 2015 09:31:37 +0000 (11:31 +0200)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 25 Jun 2015 22:31:26 +0000 (22:31 +0000)
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>

src/net/http/serve_test.go
src/net/http/server.go

index d48ea686d9e5be8e6abbdbe8a03594b5b2e32b81..de40559ff1939671083546c7d426083a288ecdc3 100644 (file)
@@ -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()
index e1a2825a6a210cb50a9249b6c621126878147605..71154ec2be5ff8345556de609fb1f017d1ed00e7 100644 (file)
@@ -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
+
+}