Question

I've always been told you should zip the data to be more efficient. On the input size, this is relatively easy, as shown below:

HttpURLConnection urlConnection=(HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestProperty("Accept-Encoding", "gzip");
InputStream instream=urlConnection.getInputStream();
Map<String, List<String>> headers = urlConnection.getHeaderFields();
List<String> contentEncodings=headers.get("Content-Encoding");
boolean hasGzipHeader=false;
if (contentEncodings!=null) {
    for (String header:contentEncodings) {
        if (header.equalsIgnoreCase("gzip")) {
            hasGzipHeader=true;
            break;
        }
    }
}
if (hasGzipHeader) {
    instream = new GZIPInputStream(instream);
}

The output side seems a tad bit trickier. I've found how to just send a general Post statement output, as follows:

HttpsURLConnection conn = (HttpsURLConnection) url
        .openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Accept-Encoding", "gzip");
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
        "application/x-www-form-urlencoded");

OutputStream os = conn.getOutputStream();
os.write(getQuery(results).getBytes(Charset.forName("UTF8")));

private String getQuery(List<BasicNameValuePair> params)
        throws UnsupportedEncodingException {
    StringBuilder result = new StringBuilder();
    boolean first = true;
    for (BasicNameValuePair pair : params) {
        if (first)
            first = false;
        else
            result.append("&");

        result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
        result.append("=");
        result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
    }
    return result.toString();
}

But I can't figure out how to get the output stream gziped, if it's even possible. I can't figure out how to tell if the server will accept the connection, and how to tell the server that the data is zipped. It's easy enough to send the data encoded, as follows:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream(baos);
gzipStream.write(getQuery(results).getBytes(
        Charset.forName("UTF8")));
os.write(baos.toByteArray());
Was it helpful?

Solution

Yes, for input (download) the Android implementation of HttpURLConnection does gunzip transparently. But for output (upload) this is not done automatically. The client cannot know whether server supports compression. So you have to do it manually and you have to be sure that your servers understand the request.

You can find an example at DavidWebb.

The code to gzip the payload:

static byte[] gzip(byte[] input) {
    GZIPOutputStream gzipOS = null;
    try {
        ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
        gzipOS = new GZIPOutputStream(byteArrayOS);
        gzipOS.write(input);
        gzipOS.flush();
        gzipOS.close();
        gzipOS = null;
        return byteArrayOS.toByteArray();
    } catch (Exception e) {
        throw new WebbException(e); // <-- just a RuntimeException
    } finally {
        if (gzipOS != null) {
            try { gzipOS.close(); } catch (Exception ignored) {}
        }
    }
}

And you have to set the following header:

connection.setRequestProperty("Content-Encoding", "gzip");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top