Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I explicitly disable chunked streaming mode for HTTP connections in Android?

I'm targeting a REST web service from Android 4.0 using HttpsURLConnection. This works fine unless I try to POST something. This is the relevant code section:

   connection.setDoOutput(true);
   connection.setChunkedStreamingMode(0);

   ByteArrayOutputStream out = new ByteArrayOutputStream();
   serializeObjectToStream(out, object);
   byte[] array = out.toByteArray();
   connection.getOutputStream().write(array, 0, array.length);

This throws the following exception:

   java.net.HttpRetryException: Cannot retry streamed HTTP body

From debugging I realized that the output stream I get via connection.getOuputStream() is of type ChunkedOutputStream and from digging in Androids source code I figured that if a request needs to be retried (for whatever reason), it pokes with the above exception, because it figures out that it is not using a RetryableOutputStream that it wants there.

The question is now: How do I make my HttpsURLConnection return such a RetryableOutputStream, or rather, how can I prevent chunked request encoding properly? I thought I did that already with setChunkedStreamingMode(0), but apparently this is not the case...

[edit]

No, the implementation of java.net.HTTPUrlConnection ignores a streaming mode of 0 or lower:

 public void setChunkedStreamingMode(int chunkLength) {
    [...]
    if (chunkLength <= 0) {
        this.chunkLength = HttpEngine.DEFAULT_CHUNK_LENGTH;
    } else {
        this.chunkLength = chunkLength;
    }
}
like image 713
Thomas Keller Avatar asked Aug 22 '12 10:08

Thomas Keller


2 Answers

Bummer! The solution is to not call setChunkedStreamingMode() (or even setFixedStreamingMode()) from the client code at all! "-1" are the internal default values for fixedLength and chunkedLength and cannot be set client-side, because setting a value lower or equal to "0" lets it default to HttpEngine.DEFAULT_CHUNK_LENGTH (or throws an exception in the fixed streaming mode case).

like image 74
Thomas Keller Avatar answered Sep 26 '22 07:09

Thomas Keller


The solution is to set a Content-Length header (which may be set by this next part) and call setFixedLengthStreamingMode with the proper length of the POST message you intend to send.

See the "streaming mode" section in this SO FAQ:

Using java.net.URLConnection to fire and handle HTTP requests

like image 25
Christopher Schultz Avatar answered Sep 23 '22 07:09

Christopher Schultz