diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index d48ea686d9e..de40559ff19 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -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() diff --git a/src/net/http/server.go b/src/net/http/server.go index e1a2825a6a2..71154ec2be5 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -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 + +}