Urlconnection Getcontentlength() Is Returning a Negative Value

URLConnection getContentLength() is returning a negative value

There are two possible common explanations for this:

  1. The content length is not known. Or more specifically, the server is not setting a "Content-Length" header in the response message.

  2. The content length is greater than Integer.MAX_VALUE. If that happens, getContentLength() returns -1. (The javadocs recommend that getContentLengthLong() is used instead of getContentLength() to avoid that problem.)

Either way, it is better to NOT preallocate a fixed sized byte array to hold the image.

  • One alternative is to create a local ByteArrayOutputStream and copy bytes read from the socket to that. Then call toByteArray to grab the full byte array.

  • Another alternative is to save the data in a temporary file in the file system.

Apparently a common underlying cause of this is that some implementations will by default request "gzip" encoding for the response data. That forces the server to set the content length to -1. You can prevent that like this:

connection.setRequestProperty("Accept-Encoding", "identity");

... but that means that the response won't be compressed. So that is
(IMO) a substandard solution.


Your existing client-side code is broken in another respect as well. If you get an IOException or some other exception, the code block will "exit abnormally" without closing the URLConnection. This will result in the leakage of a file descriptor. Do this too many times and your application will fail due to exhaustion of file descriptors ... or local port numbers.

It is best practice to use a try / finally to ensure that URLConnections, Sockets, Streams and so on that tie down external resources are ALWAYS closed.


Preallocating a buffer based on the (purported) content length sets you up for a denial of service attack. Imagine what if the bad guys send you a lot of request with dangerously large "Content-Length" headers and then slow-send the data. OOMEs or worse.

URLConnection.getContentLength() returns -1

If the server is sending down the response using Chunked Transfer Encoding, you will not be able to pre-calculate the size. The response is streamed, and you'll just have to allocate a buffer to store the image until the stream is complete. Note that you should only do this if you can guarantee that the image is small enough to fit into memory. Streaming the response to flash storage is a pretty reasonable option if the image may be large.

In-memory solution:

private static final int READ_SIZE = 16384;

byte[] imageBuf;
if (-1 == contentLength) {
byte[] buf = new byte[READ_SIZE];
int bufferLeft = buf.length;
int offset = 0;
int result = 0;
outer: do {
while (bufferLeft > 0) {
result = is.read(buf, offset, bufferLeft);
if (result < 0) {
// we're done
break outer;
}
offset += result;
bufferLeft -= result;
}
// resize
bufferLeft = READ_SIZE;
int newSize = buf.length + READ_SIZE;
byte[] newBuf = new byte[newSize];
System.arraycopy(buf, 0, newBuf, 0, buf.length);
buf = newBuf;
} while (true);
imageBuf = new byte[offset];
System.arraycopy(buf, 0, imageBuf, 0, offset);
} else { // download using the simple method

In theory, if the Http client presents itself as HTTP 1.0, most servers will switch back to non-streaming mode, but I don't believe this is a possibility for URLConnection.

Android: URLConnection.getContentLength() giving incorrect value

The description of .getContentLength() is that it returns the value of the Content-Length header field. In ordinary circumstances, this should match the amount of data available to be read. However...

(1) The header may not be present if chunked-encoding is being used to send the data. In this case, .getContentLength() returns -1 so that appears not to be the case here.

(2) By default, the implementation of HttpURLConnection requests that servers use gzip compression and it automatically decompresses the data for callers of getInputStream(). The Content-Encoding and Content-Length response headers are cleared in this case.

The last sentence seems to indicate that this also is not the case here, because you are not getting -1 from .getContentLength()`, but the relative sizes (1273 / 10136) make me suspicious...

One test of this would be to disabled Gzip encoding by setting the acceptable encodings in the request header with:

urlConnection.setRequestProperty("Accept-Encoding", "identity");

Another would be to 'snoop' the network traffic to observer the http headers and amount of data for clues.

BTW, url.openStream() is a convenience for url.openConnection().getInputStream().

httpurlConnection.getContentLength() return -1

just delete line : httpConnection.setDoOutput(true); or set false

Thanks EJP

Why is my urlConnection.getContentLength size always -1?

You need to pass the correct latitude and longitude values for this. I could do this with your code. I tried passing Longitude and latitude values corrected up to 7 decimal points. I tried this.

Try with following.
Pune = > srcLat = 18.4577015;
Pune = > srcLong = 73.8552158;

Mumbai = > destLat = 19.017576;
Mumbai = > destLong = 72.8562427;

Result: Before parse size:47555

Android getContentLength always return -1 when downloading apk file

The content length is not always available because by default Android request a GZIP compressed response. Source: Android documentation.

Quoting the link:

By default, this implementation of HttpURLConnection requests that
servers use gzip compression and it automatically decompresses the
data for callers of getInputStream(). The Content-Encoding and
Content-Length response headers are cleared in this case. Gzip
compression can be disabled by setting the acceptable encodings in the
request header:

urlConnection.setRequestProperty("Accept-Encoding", "identity");

Setting the Accept-Encoding request header explicitly disables
automatic decompression and leaves the response headers intact;
callers must handle decompression as needed, according to the
Content-Encoding header of the response.

getContentLength() returns the number of bytes transmitted and cannot
be used to predict how many bytes can be read from getInputStream()
for compressed streams. Instead, read that stream until it is
exhausted, i.e. when read() returns -1.

Whether or not the response then actually is compressed depends on the server of course.



Related Topics



Leave a reply



Submit