-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HttpComponentsClientHttpRequestFactory does not set Content-Length: 0 #32678
Comments
Looking into it some more, in This is because of this check: Line 91 in 019ce44
In 6.1.5, this check would be true when using |
Before investigating more we should question this requirement. The previous behavior was changed because it was considered invalid with regards to the spec. Is there anything supporting this behavior in clients in general? |
Sadly this isn't changeable from my team. We're trying to call an external API that is very resistant to change, and they've always required sending e.g. this curl works:
and so does this one:
but this one does not:
So having some way to send |
We're trying to call in our code with the following currently HttpEntity<Object> entity = new HttpEntity<>("", headers);
ResponseEntity<Response> response = restTemplate.exchange(url, HttpMethod.POST, entity, Response.class); I could understand not sending Also, for what it's worth, we do get a |
This seems related to, or perhaps even in contradiction of, #32650. |
I don't think this is contradicted by #32650, for instance, in #32650 (comment) @nhmarujo lays out almost exactly the same as what I would expect. Thought that is somewhat contradicted by #32650 (comment), so maybe not... in #32650, the conclusion seems to me (and it seems to me that it works this way with
Whereas currently with
Hopefully those that worked on #32650 can comment, as maybe I'm misunderstanding something here. |
Same here. The changes in the content-length headers behaviour were breaking our system several times now for the last month. Not being able to set a guaranteed content-length header would be a huge deal for us. Because our central NoSql Database expects a content-length set for requests. Even when no body is contained. With the current behaviour we are not able to update spring from now on. Or refactor the whole system to move away from using the rest template. Meaning to exchange the whole data access layer. Thats really a big deal. |
There is no problem with the Content-Length being 0 with Empty Body. (That doesn't mean you should set) The RFC document defines a value greater than or equal to zero as a valid value. In my opinion, this change (#32650 , b3a4567) has the following meaning:
(In previous behavior, there was no way to not attach Content-Length) //on prev code
if ( headers.getContentLength() < 0) { // check if there is no content-length header
headers.setContentLength(bytes.length);
} I think there is no problem with that change itself. But if "content-length = 0" cannot be set explicitly, I think this is a problem and a point to be corrected. I'm not sure because I didn't see the full detailed code flow, but if I read the first comment, I somewhat don't understand why these codes were written. link I think @tholinka 's concept is correct. does NOT set header:
DOES set header:
Hi @nhmarujo!! Have any Idea?? |
I think this code seems to have been written on the assumption that the Content-Length will be recalculated and added unconditionally in this part that has been changed (#32650 , b3a4567 ) It will no longer be added unconditionally, it seems necessary to make appropriate changes. I think there are some ways. (Again, adding the content-length header automatically to all requests doesn't seem right.)
It just came to my mind immediately and I need other's opinions. |
I, too, suffer from this regression because a legacy system which is called by a service I’m helping to maintain requires I think, for empty POST/PUT/PATCH requests, the Content-Length header should be set to 0. This is supported by the HTTP RFC#9110. It says:
Note that, „when the method defines a meaning for enclosed content“ in the first sentence refers to e.g. POST/PUT/PATCH requests. And „the method semantics do not anticipate such data“ in the last sentence refers to e.g. GET requests. PS: We can also dig into the history of the HTTP RFCs. For instance, RFC#2616 said about the
And section 4.4 said:
|
@jbretsch note however that what you just posted speaks in favour of #32650 , b3a4567
That issue was specifically about a POST without a body (not empty, but absent!). 🙂 |
No, it does not. That is because with "the method semantics do not anticipate such data" they mean e.g. GET requests which normally have no body. POST/PUT/PATCH requests fall under "when the method defines a meaning for enclosed content". When the RFC speaks about "method", it does not speak about different resources and their specific semantics given by the implementing service. It speaks about HTTP methods, i.e. HTTP verbs. PS: Also, from the perspective of the HTTP RFC, there is no difference between a POST request with an empty body and POST request with an absent body. |
So say I have 2 POSTS with no content, but one with |
I see nothing in section 8.3 Content-Type that suggests that those two requests should have different semantics. I would also still maintain the claim that from the perspective of the HTTP RFC, there is no difference between a POST request with an empty body and a POST request with an absent body. Do you see where the HTTP RFC makes a distinction between empty and absent body? |
I think this comment on stackoverflow does shed some light with some RFC quotes https://stackoverflow.com/a/78182957 Let me know your thoughts 🙂 |
The argument in https://stackoverflow.com/a/78182957 assumes that a client is free to choose whether to include the I'm not convinced that it would be a good idea to actually implement a POST resource which behaves differently for absent and empty requests. But I'm fine with settling on: The HTTP RFC allows that. The question remains how Spring should behave. I agree with #32678 (comment) which expects a HttpEntity<Object> entity = new HttpEntity<>("", headers);
ResponseEntity<Response> response = restTemplate.exchange(url, HttpMethod.POST, entity, Response.class); I think, it would be pragmatic to restore this behavior while simultaneously allowing people to differentiate between absent and empty request bodies by having Spring exclude the HttpEntity<Object> entity = new HttpEntity<>(null, headers);
ResponseEntity<Response> response = restTemplate.exchange(url, HttpMethod.POST, entity, Response.class); |
Yes, that is the suggestion I was trying to make - to avoid the second one from having the |
I had another look and tested the following code snippet with various combinations of request factories and checking the "Content-Length" header value received by the server: ResponseEntity<String> response = restClient.post().uri("http://localhost:8080/test").retrieve().toEntity(String.class); Spring Framework 6.1.5We can see two inconsistencies, one with
Spring Framework 6.1.6The
I have tested a patch in Empty vs missing request bodyI think the use case for Several contracts in Spring Framework do not make that difference, for example the
class ContentLengthInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
if (body.length == 0) {
request.getHeaders().setContentLength(0);
}
return execution.execute(request, body);
}
} |
We have discussed this as a team and we think that the issue might not be in the FYI we just reopened #32650 and we might revert the change there. |
Affects: 6.1.6
I have an API that requires sending a
Content-Length: 0
when the body is null/empty.When we previously upgraded to Spring Boot 3 / Spring 6, we changed our
RestTemplate
to usenew BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory())
as the request factory in order to ensure that aContent-Length
was set.This worked on 6.1.5, but on upgrading to 6.1.6 we are no longer sending the
Content-Length
header.Stepping through the code with a debugger, this changed in 019ce44 / gh-32612.
spring-framework/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java
Line 58 in 019ce44
I can force the old behavior if I do the following, which leads me to believe it is that commit (effectively, I'm trying to just skip over the new
if
):BufferingClientHttpRequestWrapper
bufferedOutput = new byte[1];
bufferedOutput = new byte[0];
Doing this then causes the
Content-Length: 0
header to be sent as expected.I tried also manually setting
Content-Length: 0
as a header, butHttpComponentsClientHttpRequest
does not allow that, as is explicitly ignoresContent-Length
as a header.spring-framework/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequest.java
Line 110 in 019ce44
This still works as expected (
Content-Length: 0
is set) when usingSimpleClientHttpRequestFactory
, so for now I can work around this by usingnew BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())
instead. However, I would prefer to useHttpComponentsClientHttpRequestFactory
instead ofSimple
if possible.The text was updated successfully, but these errors were encountered: