Skip to content

Commit 1438225

Browse files
committed
net/http: revert overly-strict part of earlier smuggling defense
The recent https://golang.org/cl/11810 is reportedly a bit too aggressive. Apparently some HTTP requests in the wild do contain both a Transfer-Encoding along with a bogus Content-Length. Instead of returning a 400 Bad Request error, we should just ignore the Content-Length like we did before. Change-Id: I0001be90d09f8293a34f04691f608342875ff5c4 Reviewed-on: https://go-review.googlesource.com/11962 Reviewed-by: Andrew Gerrand <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 7929a0d commit 1438225

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

src/net/http/readrequest_test.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,36 @@ var reqTests = []reqTest{
178178
noError,
179179
},
180180

181+
// Tests chunked body and a bogus Content-Length which should be deleted.
182+
{
183+
"POST / HTTP/1.1\r\n" +
184+
"Host: foo.com\r\n" +
185+
"Transfer-Encoding: chunked\r\n" +
186+
"Content-Length: 9999\r\n\r\n" + // to be removed.
187+
"3\r\nfoo\r\n" +
188+
"3\r\nbar\r\n" +
189+
"0\r\n" +
190+
"\r\n",
191+
&Request{
192+
Method: "POST",
193+
URL: &url.URL{
194+
Path: "/",
195+
},
196+
TransferEncoding: []string{"chunked"},
197+
Proto: "HTTP/1.1",
198+
ProtoMajor: 1,
199+
ProtoMinor: 1,
200+
Header: Header{},
201+
ContentLength: -1,
202+
Host: "foo.com",
203+
RequestURI: "/",
204+
},
205+
206+
"foobar",
207+
noTrailer,
208+
noError,
209+
},
210+
181211
// CONNECT request with domain name:
182212
{
183213
"CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
@@ -399,11 +429,6 @@ var badRequestTests = []struct {
399429
Content-Length: 3
400430
Content-Length: 4
401431
402-
abc`)},
403-
{"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1
404-
Transfer-Encoding: chunked
405-
Content-Length: 3
406-
407432
abc`)},
408433
{"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
409434
Host: foo

src/net/http/transfer.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,6 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
430430
if !present {
431431
return nil, nil
432432
}
433-
isRequest := !isResponse
434433
delete(header, "Transfer-Encoding")
435434

436435
encodings := strings.Split(raw[0], ",")
@@ -458,12 +457,20 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
458457
// RFC 7230 3.3.2 says "A sender MUST NOT send a
459458
// Content-Length header field in any message that
460459
// contains a Transfer-Encoding header field."
461-
if len(header["Content-Length"]) > 0 {
462-
if isRequest {
463-
return nil, errors.New("http: invalid Content-Length with Transfer-Encoding")
464-
}
465-
delete(header, "Content-Length")
466-
}
460+
//
461+
// but also:
462+
// "If a message is received with both a
463+
// Transfer-Encoding and a Content-Length header
464+
// field, the Transfer-Encoding overrides the
465+
// Content-Length. Such a message might indicate an
466+
// attempt to perform request smuggling (Section 9.5)
467+
// or response splitting (Section 9.4) and ought to be
468+
// handled as an error. A sender MUST remove the
469+
// received Content-Length field prior to forwarding
470+
// such a message downstream."
471+
//
472+
// Reportedly, these appear in the wild.
473+
delete(header, "Content-Length")
467474
return te, nil
468475
}
469476

0 commit comments

Comments
 (0)