mirror of
https://github.com/golang/go.git
synced 2025-05-29 11:25:43 +00:00
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/11491 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
fe1cecfaec
commit
bf5e19fbaf
@ -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) {
|
func BenchmarkClientServer(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
@ -130,6 +130,7 @@ type conn struct {
|
|||||||
lr *io.LimitedReader // io.LimitReader(sr)
|
lr *io.LimitedReader // io.LimitReader(sr)
|
||||||
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
|
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
|
||||||
tlsState *tls.ConnectionState // or nil when not using TLS
|
tlsState *tls.ConnectionState // or nil when not using TLS
|
||||||
|
lastMethod string // method of previous request, or ""
|
||||||
|
|
||||||
mu sync.Mutex // guards the following
|
mu sync.Mutex // guards the following
|
||||||
clientGone bool // if client has disconnected mid-request
|
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()
|
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
|
var req *Request
|
||||||
if req, err = ReadRequest(c.buf.Reader); err != nil {
|
if req, err = ReadRequest(c.buf.Reader); err != nil {
|
||||||
if c.lr.N == 0 {
|
if c.lr.N == 0 {
|
||||||
@ -626,6 +632,7 @@ func (c *conn) readRequest() (w *response, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.lr.N = noLimit
|
c.lr.N = noLimit
|
||||||
|
c.lastMethod = req.Method
|
||||||
|
|
||||||
req.RemoteAddr = c.remoteAddr
|
req.RemoteAddr = c.remoteAddr
|
||||||
req.TLS = c.tlsState
|
req.TLS = c.tlsState
|
||||||
@ -2181,3 +2188,15 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func numLeadingCRorLF(v []byte) (n int) {
|
||||||
|
for _, b := range v {
|
||||||
|
if b == '\r' || b == '\n' {
|
||||||
|
n++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user