Bug 60698 - getContentLength returns -1 for requests without body
Summary: getContentLength returns -1 for requests without body
Status: RESOLVED INVALID
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Connectors (show other bugs)
Version: 8.5.x-trunk
Hardware: All All
: P2 enhancement (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-02-07 08:52 UTC by Tobias Oberlies
Modified: 2017-05-08 08:57 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Oberlies 2017-02-07 08:52:27 UTC
javax.servlet.ServletRequest.getContentLength() specifies that it would return "an integer containing the length of the request body or -1 if the length is not known". 

However Catalina's implementation of that method [1] also returns -1 for requests without request body. IMHO this violates the specification because because it is known that an attempt to read the request body will yield zero bytes.

The root cause of this problem lies in the implementation of org.apache.coyote.Request.getContentLengthLong(). This method only checks the presence of the "content-length" header and returns -1 if that header is not set. Instead, it should also test for the absence of the "transfer-encoding" header, and return 0 if that header is absent.

This would then also be compliant with what is described in the section "Message Body Length" in the HTTP standard [2]: "If this is a request message and none of the above are true, then the message body length is zero (no message body is present)."

[1] org.apache.catalina.connector.Request.getContentLength()
[2] https://tools.ietf.org/html/rfc7230#section-3.3.3
Comment 1 Remy Maucherat 2017-02-07 11:58:35 UTC
This will need to be investigated before making a change. I consider that getContentLength reflects the content-length header and "unknown" allows the current behavior.

The Tomcat code accommodates the current behavior (Request.parseParameters), and I think user code will have to check for the transfer-encoding header anyway rather to rely on -1.

Conclusion: not convinced. I'll move this to 8.5 as well.
Comment 2 Tobias Oberlies 2017-02-08 11:55:30 UTC
> I think user code will have to check for the transfer-encoding header anyway

Why is that? Do servlets care about the framing of request bodies? I don't think so. The HTTP standard even requires that the framing of the message body (i.e. if transfer-encoding is used or content-length) must not have an influence on the semantics: "Request message framing is independent of method semantics" [1] So for most servlets, framing will not make a difference.

Similarly, most servlets will not care how the absence of a request body is signaled. They will want to handle requests in the same way regardless of whether the request has a content-length: 0 header or neither content-length nor transfer-encoding header. So the servlet API should hide this detail by returning 0 on getContentLenth() in both cases.

[1] https://tools.ietf.org/html/rfc7230#section-3.3
Comment 3 Remy Maucherat 2017-02-08 13:51:14 UTC
I researched a bit in other implementations, and at this point the result reflects only the value of the content-length header.
Please do not reopen the report unless you get the Servlet EG to make an explicit clarification about this behavior.
Comment 4 Bilguun Bayarmagnai 2017-05-07 15:05:10 UTC
I'm facing exact same issue here with DELETE & PATCH requests. But investigating further, it seems like a browser issue, which is setting Content-Length: 0 on POST & PUT requests. However not on DELETE & PATCH requests which is resulting in -1, and 411 error(when using tomcat as a proxy) on the down path.
Comment 5 Tobias Oberlies 2017-05-08 08:57:58 UTC
FYI: I have opened https://java.net/jira/browse/SERVLET_SPEC-169 to discuss what the correct behaviour is from the servlet spec's POV.

@Bilguun: It is completely valid if a browser decides to send neither Content-Length nor Transfer-Encoding in a request. This is a completely valid approach, and the HTTP standard is completely clear what this means: "the message body length is zero" [1]. Unfortunately, the servlet spec is not that clear on this.

[1] https://tools.ietf.org/html/rfc7230#section-3.3.3