Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write a post statement to an HttpUrlConnection that's zipped?

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());
like image 693
PearsonArtPhoto Avatar asked Feb 24 '14 18:02

PearsonArtPhoto


People also ask

How do I upload a file using HttpURLConnection?

Setup the request: HttpURLConnection httpUrlConnection = null; URL url = new URL("http://example.com/server.cgi"); httpUrlConnection = (HttpURLConnection) url. openConnection(); httpUrlConnection. setUseCaches(false); httpUrlConnection.

Which is the following used in HttpURLConnection?

HttpURLConnection uses the GET method by default. It will use POST if setDoOutput(true) has been called. Other HTTP methods ( OPTIONS , HEAD , PUT , DELETE and TRACE ) can be used with setRequestMethod(String) .

Can I use HttpURLConnection for https?

HttpsURLConnection extends HttpURLConnection , and your connection is an instance of both. When you call openConnection() the function actually returns an HttpsURLConnection . However, because the https object extends the http one, your connection is still an instance of an HttpURLConnection .


1 Answers

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");
like image 136
hgoebl Avatar answered Oct 18 '22 20:10

hgoebl