getContentLength method in spring-web HttpHeaders class is prone to NumberFormatException. Due to some reason, my content length is not getting set in response. Hence value of content length is returned as empty string from getFirst method. When this empty string is parsed, NumberFormatException is thrown.

public long getContentLength() {
    String value = getFirst(CONTENT_LENGTH);
    return (value != null ? Long.parseLong(value) : -1);
}

Comment From: b4nnertail

The problem is that Long.parseLong() can only parse Strings, which characters are all digits (except of an additional leading minus sign). I am new to contributing and would like to solve the issue, assuming it's desirable to return a -1 in case of Content-Length = ""

Comment From: michael-o

The RFC says

Any Content-Length field value greater than or equal to zero is valid.

With Long.parseLong a client could also send -23 which is invalid.

Comment From: rashid442000

Issue is that value is empty string. And when empty string is parsed, NumberFormatException is thrown. Please find the exception below:

java.lang.NumberFormatException: For input string: ""
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.lang.Long.parseLong(Long.java:601)
        at java.lang.Long.parseLong(Long.java:631)
        at org.springframework.http.HttpHeaders.getContentLength(HttpHeaders.java:940)
...

A simple fix would do the trick:

public long getContentLength() {
    String value = getFirst(CONTENT_LENGTH);
    return (value != null && !value.isEmpty() ? Long.parseLong(value) : -1);
}

Comment From: rstoyanchev

@rashid442000 I've edited your comments to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

Comment From: rstoyanchev

Can you clarify the context in which this is happening? Is it client or server side, and is it on the request or response? In general it does make sense to be lenient with inputs, but would still be useful to know what is the origin of the "".

Comment From: rashid442000

It is happening on server side, when the response is being sent.

Origin of empty string

In one of our response filter, we were re-initializing header in response (This was a bug in our code).

In Spring 3.1, getFirst method used to return null, in case that header was not present (Reason our code was working fine).

But in Spring 5.2.3, getFirst method returns an empty string, in case the header is not present (Returning empty string is better than return null for returning a string).

Comment From: michael-o

But in Spring 5.2.3, getFirst method returns an empty string, in case the header is not present (Returning empty string is better than return null for returning a string).

Looks wrong to me if the header is not present.

Comment From: sbrannen

But in Spring 5.2.3, getFirst method returns an empty string, in case the header is not present (Returning empty string is better than return null for returning a string).

According to the Javadoc for org.springframework.http.HttpHeaders.getFirst(String), that method should return "the first header value, or null if none."

So if getFirst(String) is returning "" instead of null for a missing header, that would be a bug.

@rashid442000, are you certain that the header is not present with an empty value?

Comment From: rstoyanchev

This might be related to the fact that in 4.0.x we started checking the response to see if it has the header set which wasn't always possible in the Servlet API.

This might explain the case when coupled with:

In one of our response filter, we were re-initializing header in response (This was a bug in our code).

In other words, the header was set only in the underlying response by a filter, and the bug remained invisible is my guess.

Comment From: michael-o

@rstoyanchev Wouldn't the exception qualify for a 400?

Comment From: rstoyanchev

@michael-o I don't see a 400 here. This is entirely server-side affair with a filter adding an empty header to the response.

In terms of how HttpHeaders works, it's true that it is used for both request and response. Thinking about a server request, I highly doubt we would ever get an empty string from the underlying server request regardless of what the client sent.

In light of the fact this is actually about the response, I'm inclined to close this as "Invalid". An application bug caused an empty content-length header, which resulted in a NumberFormatException. A 500 response seems right after all.

Comment From: michael-o

@rstoyanchev From a server-side, in a Controller I would expect a 400 send back to the client. From a client-side, invalid response...

Comment From: rstoyanchev

What does from a server side in a controller mean more specifically? A controller finding a request header empty? If so that is not the case here. If otherwise then please explain what you mean.

Comment From: michael-o

@Controller
public class Controller {

  @GetMapping
  public void get(HttpHeaders headers) {
  ...headers.getContentLength();
  }
}

Comment From: rstoyanchev

I'm sorry but that's not the case here. I suspect the server will reject such a request before it even gets to us.