Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GZIPInputStream fails with IOException in Android 2.3, but works fine in all previous releases?

I updated my phone to Gingerbread today (2.3.2) and fired up an app I developed and saw that it failed to load its data. The app runs fine on every other version of Android I have tested from 1.6 to 2.2, but then an IOException in Gingerbread. Does anybody know if something changed in either GZipInputStream or URL.openStream()?

The problematic code is similar to the following:

InputStream in = null;
GZIPInputStream zin = null;
URL url = null;
try {
    url = new URL("http://www.test.com/gzipped_data.gz");
    in = url.openStream();
    zin = new GZIPInputStream(in);
}
catch (MalformedURLException e) { 
    return false;
} 
catch (IOException e) {
    return false;
}

In 1.6 to 2.2, this code works fine, in 2.3 I get an IOException with a message about the magic block being incorrect. I'm assuming something has changed with openStream that is messing up the MIME-type or something on this data. I read other places that openStream is not the most reliable way to handle HTTP connections, so this might be a good excuse to rework my connections code.

like image 540
Justin Hopper Avatar asked Oct 11 '22 15:10

Justin Hopper


1 Answers

I'm running into the same issue here. It looks like Gingerbread (2.3) changed the way GZipped streams are handled. Looking at the "magic block" characters indicates that openStream() automatically detects GZipped data and runs it through the correct stream decoder. Of course, if you attempt to run another GZIP decoder on the same stream, that will fail with an IOException.

There are a couple ways to handle this. The first way is to switch to HttpClient/HttpGet. BUT there is no guarantee that this also won't change in the future. Basically, that is a hack to get it working again. A more complete solution might be to do:

InputStream in = url.openStream();
GZIPInputStream zin;
try {
    zin = (GZIPInputStream)in;
} catch (Exception e) {
    zin = new GZIPInputStream(in);
}

For older versions of Android, an exception fires while attempting the cast and, on newer versions of Android, the cast succeeds. Abusing an exception handler this way is not pretty but it works.

This, of course, will be a problem for underlying data that is compressed or binary data that looks like it is GZIP compressed data. The Android devs think this change isn't a bug:

http://code.google.com/p/android/issues/detail?id=16227

I disagree. This is severe breakage.

like image 168
Bibbity Bobbity Boo Avatar answered Oct 19 '22 00:10

Bibbity Bobbity Boo