Sending a body with a GET request using http.request cannot be received using http.server
jameshartig opened this issue · 12 comments
When you send a GET request using http.request to a Node.js server using the built-in http server, the parser throws an error:
HTTP 14997: parse error
NET 14997: destroy { [Error: Parse Error] bytesParsed: 87, code: 'HPE_INVALID_METHOD' }
Presumably because there was no Content-Length
or Transfer-Encoding
header. There was neither one of those headers because the http client code sets useChunkedEncodingByDefault
to false when the method is GET
. The parser hits the end of the headers and then immediately starts assuming any more data is a new HTTP request instead of it possibly being the body.
If you make the request and explicitly set the Content-Length
using setHeader
then no parse error is thrown. The HTTP spec says:
A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests.
But as far as I can tell, onlyHEAD
explicitly states it cannot have a body. The server is following the spec, however:
The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers.
I'm not sure what the fix is here since turning on chunked encoding for GET might make GET's slower and I also realize this is an unintended use case (or bug in user-land) but I thought I'd bring it up.
Can you provide a complete example to reproduce the issue?
HPE_INVALID_METHOD
means that an invalid method (like GEM
or GETA
rather than GET
) was received. Sample code triggering the error would be immensely helpful.
Here's a quick and easy reproduction case:
https://gist.github.com/fastest963/048c6108c83f46e77eaa
@Trott The reason its throwing HPE_INVALID_METHOD
was mentioned originally but I'll reiterate: Since the parser didn't get a Content-Length
or Transfer-Encoding
it immediately ends after reading the second \r\n
and then it starts assuming the next bytes are another request instead of assuming that its the body from the first request.
The reproduction code clarifies everything. Thanks for doing that.
I can definitely see a case for considering this a bug in the userland code and not in Node. But even so, I do wonder if the error message can at least be improved or clarified somehow. I'm not sure there's an easy way to do that without possibly hitting false positives, though.
IMHO this is behaving as expected.
I know quite a few api services that accept bodies on GET requests (where clauses, etc). If I were to implement those services in nodejs, this would fail then?
@tflanagan If you sent a Content-Length
or Transfer-Encoding
then it would still work. I mainly filed the because there's a "bug" when requesting and receiving via the default APIs in node. If you're using a non-node client and it sends one of those headers then you're fine.
Somewhat related to nodejs/node-v0.x-archive#5767 and nodejs/node-v0.x-archive#7575.
From RFC7231: A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
Sending a body in a GET has always led to undefined behavior. As far as I can tell, there's no bug here. Closing but can reopen if necessary. /cc @nodejs/http
FYI, in my case I was sending body data in a GET request without sending Content-Length
.
@pagalasoujanya Don't hijack unrelated issues.
(Note: I hate having to bring this up, but it's just that I wasted a few hours today troubleshooting why an API returned a different result when I used curl vs node client.)
From RFC7231
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
This does not read to me as a prohibition (certainly less so than language in earlier RFC) and considering that there are major applications (e.g. Elasticsearch) that use GET with body for queries, node should add a Content-Length header on a GET request with a body.