rest
rest copied to clipboard
Response.getLength() limited to int max value (~2GB)
The "Content-Length" HTTP header provides the length of the body expressed in bytes. There seems to be no limitation in the HTTP specifications about that value.
In the JAX-RS API, this value is available through the getter getLength()
of the Response
class, and the returned value is an int
(32-bits signed integer) which support a maximum positive value of 2 147 483 647. It's around 2 GB, so it can easily be exceeded nowadays.
An improvement would be that the getLength()
method return a long
which would push the limit to 9 EB (1018 bytes).
This is what is done by the Apache HttpClient implementation (see org.apache.http.HttpEntity.getContentLength()
here).
Changing the signature of int getLength()
to long getLength()
would require all classes extending Response
to be changed. On example is InboundJaxrsResponse
in Jersey.
I am not sure if this is a good idea.
Of course changing the API does have impacts. Why would it not be a good idea though?
Am I in the right place to ask for a correction of small flaw in the JAX-RS API?
Also there may have been real motivations for int
instead of long
, that I'm not aware of, when the API was designed, and I'm quite inclined to hear them.
Another approach would be be to add a long getLengthLong()
in the way it is done here for Servlets.
Am I in the right place to ask for a correction of small flaw in the JAX-RS API?
Yep, you're in the right place. :)
Of course changing the API does have impacts. Why would it not be a good idea though?
If we were designing from scratch, I would agree that long
is preferable to int
, but making that change now would break backwards compatibility.
Another approach would be be to add a long getLengthLong() in the way it is done here for Servlets.
I think this is reasonable. It resolves the backwards compatibility issue and still provides the convenience of returning large content length values.
In the meantime, if you need a workaround on the existing APIs, something like this might help you:
public static long getLengthLong(Response r) {
String contentLength = r.getHeaderString(HttpHeaders.CONTENT_LENGTH);
if (contentLength != null) try {
return Long.parseLong(contentLength);
} catch (NumberFormatException ignore) {}
return -1;
}
Of course changing the API does have impacts. Why would it not be a good idea though?
As JAX-RS is not just some library you can simply switch in your app, but actually is contract between millions of existing applications and the existing application servers, non-backwards-compatible changes are simply a no-go for us (unless we defer your request to a major version like 4.x, which is far, far away). But we can add new methods, certainly. :-)
Having said that I am +-0 for your proposal of adding getLengthLong
for the time being, i. e. it would be OK for me but I also can wait for 4.0.
Thank you @andymc12 for the workaround snippet.
Actually, I had already done something similar, but using much 3rd-party syntactic sugar:
import com.google.common.primitives.Longs;
import static com.google.common.base.Strings.nullToEmpty;
import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
import static org.apache.commons.lang3.math.NumberUtils.INTEGER_ZERO;
...
final Long httpContentlength = Longs.tryParse(nullToEmpty(httpResponse.getHeaderString(CONTENT_LENGTH)));
if (httpContentlength == null || httpContentlength < INTEGER_ZERO)
{
throw new DepotFichierException("Abandon de la recopie du fichier. Sa taille n'est pas fournie par l'entête HTTP.");
}