Handle gzip in DefaultHttpDataSource.

Setting the requested encoding in all cases ensures we receive the relevant
response headers indicating whether gzip was used. Doing that allows to
detect the content length in cases where gzip was requested, but the server
replied with uncompressed content.

PiperOrigin-RevId: 250660890
This commit is contained in:
tonihei 2019-05-30 11:42:20 +01:00 committed by Toni
parent 00b26a51df
commit b8ec05aea1
2 changed files with 16 additions and 10 deletions

View File

@ -466,7 +466,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0; bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0;
// Calculate the content length. // Calculate the content length.
if (!getIsCompressed(responseInfo)) { if (!isCompressed(responseInfo)) {
if (dataSpec.length != C.LENGTH_UNSET) { if (dataSpec.length != C.LENGTH_UNSET) {
bytesRemaining = dataSpec.length; bytesRemaining = dataSpec.length;
} else { } else {
@ -626,7 +626,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
} }
requestBuilder.addHeader("Range", rangeValue.toString()); requestBuilder.addHeader("Range", rangeValue.toString());
} }
// TODO: Uncomment when https://bugs.chromium.org/p/chromium/issues/detail?id=767025 is fixed // TODO: Uncomment when https://bugs.chromium.org/p/chromium/issues/detail?id=711810 is fixed
// (adjusting the code as necessary). // (adjusting the code as necessary).
// Force identity encoding unless gzip is allowed. // Force identity encoding unless gzip is allowed.
// if (!dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_GZIP)) { // if (!dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_GZIP)) {
@ -655,7 +655,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
currentConnectTimeoutMs = clock.elapsedRealtime() + connectTimeoutMs; currentConnectTimeoutMs = clock.elapsedRealtime() + connectTimeoutMs;
} }
private static boolean getIsCompressed(UrlResponseInfo info) { private static boolean isCompressed(UrlResponseInfo info) {
for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) { for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) {
if (entry.getKey().equalsIgnoreCase("Content-Encoding")) { if (entry.getKey().equalsIgnoreCase("Content-Encoding")) {
return !entry.getValue().equalsIgnoreCase("identity"); return !entry.getValue().equalsIgnoreCase("identity");

View File

@ -41,6 +41,7 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
/** /**
* An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}. * An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}.
@ -305,7 +306,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0; bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0;
// Determine the length of the data to be read, after skipping. // Determine the length of the data to be read, after skipping.
if (!dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_GZIP)) { boolean isCompressed = isCompressed(connection);
if (!isCompressed) {
if (dataSpec.length != C.LENGTH_UNSET) { if (dataSpec.length != C.LENGTH_UNSET) {
bytesToRead = dataSpec.length; bytesToRead = dataSpec.length;
} else { } else {
@ -315,14 +317,16 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
} }
} else { } else {
// Gzip is enabled. If the server opts to use gzip then the content length in the response // Gzip is enabled. If the server opts to use gzip then the content length in the response
// will be that of the compressed data, which isn't what we want. Furthermore, there isn't a // will be that of the compressed data, which isn't what we want. Always use the dataSpec
// reliable way to determine whether the gzip was used or not. Always use the dataSpec length // length in this case.
// in this case.
bytesToRead = dataSpec.length; bytesToRead = dataSpec.length;
} }
try { try {
inputStream = connection.getInputStream(); inputStream = connection.getInputStream();
if (isCompressed) {
inputStream = new GZIPInputStream(inputStream);
}
} catch (IOException e) { } catch (IOException e) {
closeConnectionQuietly(); closeConnectionQuietly();
throw new HttpDataSourceException(e, dataSpec, HttpDataSourceException.TYPE_OPEN); throw new HttpDataSourceException(e, dataSpec, HttpDataSourceException.TYPE_OPEN);
@ -516,9 +520,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
connection.setRequestProperty("Range", rangeRequest); connection.setRequestProperty("Range", rangeRequest);
} }
connection.setRequestProperty("User-Agent", userAgent); connection.setRequestProperty("User-Agent", userAgent);
if (!allowGzip) { connection.setRequestProperty("Accept-Encoding", allowGzip ? "gzip" : "identity");
connection.setRequestProperty("Accept-Encoding", "identity");
}
if (allowIcyMetadata) { if (allowIcyMetadata) {
connection.setRequestProperty( connection.setRequestProperty(
IcyHeaders.REQUEST_HEADER_ENABLE_METADATA_NAME, IcyHeaders.REQUEST_HEADER_ENABLE_METADATA_NAME,
@ -747,4 +749,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
} }
} }
private static boolean isCompressed(HttpURLConnection connection) {
String contentEncoding = connection.getHeaderField("Content-Encoding");
return "gzip".equalsIgnoreCase(contentEncoding);
}
} }