mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix content length calculation for gzipped files
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=134011959
This commit is contained in:
parent
57a2749a9d
commit
f2cf086d76
2 changed files with 85 additions and 31 deletions
|
|
@ -109,7 +109,7 @@ public final class CronetDataSourceTest {
|
||||||
@Mock
|
@Mock
|
||||||
private Predicate<String> mockContentTypePredicate;
|
private Predicate<String> mockContentTypePredicate;
|
||||||
@Mock
|
@Mock
|
||||||
private TransferListener mockTransferListener;
|
private TransferListener<CronetDataSource> mockTransferListener;
|
||||||
@Mock
|
@Mock
|
||||||
private Clock mockClock;
|
private Clock mockClock;
|
||||||
@Mock
|
@Mock
|
||||||
|
|
@ -172,8 +172,8 @@ public final class CronetDataSourceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testOpeningTwiceThrows() throws HttpDataSourceException, IllegalStateException {
|
public void testOpeningTwiceThrows() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
assertConnectionState(CronetDataSource.IDLE_CONNECTION);
|
assertConnectionState(CronetDataSource.IDLE_CONNECTION);
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
@ -183,7 +183,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallbackFromPreviousRequest() throws HttpDataSourceException {
|
public void testCallbackFromPreviousRequest() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
dataSourceUnderTest.close();
|
dataSourceUnderTest.close();
|
||||||
|
|
@ -217,7 +217,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestStartCalled() throws HttpDataSourceException {
|
public void testRequestStartCalled() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
verify(mockCronetEngine).createRequest(
|
verify(mockCronetEngine).createRequest(
|
||||||
|
|
@ -234,7 +234,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestHeadersSet() throws HttpDataSourceException {
|
public void testRequestHeadersSet() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
|
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
|
||||||
testResponseHeader.put("Content-Length", Long.toString(5000L));
|
testResponseHeader.put("Content-Length", Long.toString(5000L));
|
||||||
|
|
@ -252,13 +252,29 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOpen() throws HttpDataSourceException {
|
public void testRequestOpen() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testDataSpec));
|
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testDataSpec));
|
||||||
assertConnectionState(CronetDataSource.OPEN_CONNECTION);
|
assertConnectionState(CronetDataSource.OPEN_CONNECTION);
|
||||||
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec);
|
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequestOpenGzippedCompressedReturnsDataSpecLength()
|
||||||
|
throws HttpDataSourceException {
|
||||||
|
testResponseHeader.put("Content-Encoding", "gzip");
|
||||||
|
testUrlResponseInfo = createUrlResponseInfo(200); // statusCode
|
||||||
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
|
// Data spec's requested length, 5000. Test response's length, 16,000.
|
||||||
|
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
|
||||||
|
|
||||||
|
assertEquals(5000 /* contentLength */, dataSourceUnderTest.open(testDataSpec));
|
||||||
|
assertConnectionState(CronetDataSource.OPEN_CONNECTION);
|
||||||
|
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOpenFail() {
|
public void testRequestOpenFail() {
|
||||||
mockResponseStartFailure();
|
mockResponseStartFailure();
|
||||||
|
|
@ -295,7 +311,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOpenValidatesStatusCode() {
|
public void testRequestOpenValidatesStatusCode() {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
testUrlResponseInfo = createUrlResponseInfo(500); // statusCode
|
testUrlResponseInfo = createUrlResponseInfo(500); // statusCode
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -312,7 +328,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOpenValidatesContentTypePredicate() {
|
public void testRequestOpenValidatesContentTypePredicate() {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
when(mockContentTypePredicate.evaluate(anyString())).thenReturn(false);
|
when(mockContentTypePredicate.evaluate(anyString())).thenReturn(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -329,7 +345,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOpenValidatesContentLength() {
|
public void testRequestOpenValidatesContentLength() {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
// Data spec's requested length, 5000. Test response's length, 16,000.
|
// Data spec's requested length, 5000. Test response's length, 16,000.
|
||||||
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
|
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
|
||||||
|
|
@ -348,7 +364,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostRequestOpen() throws HttpDataSourceException {
|
public void testPostRequestOpen() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE);
|
dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE);
|
||||||
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testPostDataSpec));
|
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testPostDataSpec));
|
||||||
|
|
@ -358,7 +374,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostRequestOpenValidatesContentType() {
|
public void testPostRequestOpenValidatesContentType() {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dataSourceUnderTest.open(testPostDataSpec);
|
dataSourceUnderTest.open(testPostDataSpec);
|
||||||
|
|
@ -370,7 +386,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostRequestOpenRejects307Redirects() {
|
public void testPostRequestOpenRejects307Redirects() {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockResponseStartRedirect();
|
mockResponseStartRedirect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -384,7 +400,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestReadTwice() throws HttpDataSourceException {
|
public void testRequestReadTwice() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
@ -406,7 +422,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecondRequestNoContentLength() throws HttpDataSourceException {
|
public void testSecondRequestNoContentLength() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
byte[] returnedBuffer = new byte[8];
|
byte[] returnedBuffer = new byte[8];
|
||||||
|
|
@ -437,7 +453,23 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithOffset() throws HttpDataSourceException {
|
public void testReadWithOffset() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
mockReadSuccess();
|
||||||
|
|
||||||
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
||||||
|
byte[] returnedBuffer = new byte[16];
|
||||||
|
int bytesRead = dataSourceUnderTest.read(returnedBuffer, 8, 8);
|
||||||
|
assertArrayEquals(prefixZeros(buildTestDataArray(0, 8), 16), returnedBuffer);
|
||||||
|
assertEquals(8, bytesRead);
|
||||||
|
verify(mockTransferListener).onBytesTransferred(dataSourceUnderTest, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadWithUnsetLength() throws HttpDataSourceException {
|
||||||
|
testResponseHeader.remove("Content-Length");
|
||||||
|
testUrlResponseInfo = createUrlResponseInfo(200); // statusCode
|
||||||
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
@ -451,7 +483,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadReturnsWhatItCan() throws HttpDataSourceException {
|
public void testReadReturnsWhatItCan() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
@ -465,7 +497,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClosedMeansClosed() throws HttpDataSourceException {
|
public void testClosedMeansClosed() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
|
|
@ -493,7 +525,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverread() throws HttpDataSourceException {
|
public void testOverread() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadSuccess();
|
mockReadSuccess();
|
||||||
|
|
||||||
// Ask for 16 bytes
|
// Ask for 16 bytes
|
||||||
|
|
@ -680,7 +712,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExceptionFromTransferListener() throws HttpDataSourceException {
|
public void testExceptionFromTransferListener() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
|
|
||||||
// Make mockTransferListener throw an exception in CronetDataSource.close(). Ensure that
|
// Make mockTransferListener throw an exception in CronetDataSource.close(). Ensure that
|
||||||
// the subsequent open() call succeeds.
|
// the subsequent open() call succeeds.
|
||||||
|
|
@ -699,7 +731,7 @@ public final class CronetDataSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadFailure() throws HttpDataSourceException {
|
public void testReadFailure() throws HttpDataSourceException {
|
||||||
mockResponesStartSuccess();
|
mockResponseStartSuccess();
|
||||||
mockReadFailure();
|
mockReadFailure();
|
||||||
|
|
||||||
dataSourceUnderTest.open(testDataSpec);
|
dataSourceUnderTest.open(testDataSpec);
|
||||||
|
|
@ -726,7 +758,7 @@ public final class CronetDataSourceTest {
|
||||||
}).when(mockUrlRequest).getStatus(any(UrlRequest.StatusListener.class));
|
}).when(mockUrlRequest).getStatus(any(UrlRequest.StatusListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mockResponesStartSuccess() {
|
private void mockResponseStartSuccess() {
|
||||||
doAnswer(new Answer<Object>() {
|
doAnswer(new Answer<Object>() {
|
||||||
@Override
|
@Override
|
||||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
|
|
||||||
|
|
@ -300,15 +300,20 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou
|
||||||
try {
|
try {
|
||||||
validateResponse(info);
|
validateResponse(info);
|
||||||
responseInfo = info;
|
responseInfo = info;
|
||||||
// Check content length.
|
|
||||||
contentLength = getContentLength(info.getAllHeaders());
|
if (isCompressed(info)) {
|
||||||
// If a specific length is requested and a specific length is returned but the 2 don't match
|
contentLength = currentDataSpec.length;
|
||||||
// it's an error.
|
} else {
|
||||||
if (currentDataSpec.length != C.LENGTH_UNSET
|
// Check content length.
|
||||||
&& contentLength != C.LENGTH_UNSET
|
contentLength = getContentLength(info.getAllHeaders());
|
||||||
&& currentDataSpec.length != contentLength) {
|
// If a specific length is requested and a specific length is returned but the 2 don't match
|
||||||
throw new OpenException("Content length did not match requested length", currentDataSpec,
|
// it's an error.
|
||||||
getCurrentRequestStatus());
|
if (currentDataSpec.length != C.LENGTH_UNSET
|
||||||
|
&& contentLength != C.LENGTH_UNSET
|
||||||
|
&& currentDataSpec.length != contentLength) {
|
||||||
|
throw new OpenException("Content length did not match requested length", currentDataSpec,
|
||||||
|
getCurrentRequestStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentLength > 0) {
|
if (contentLength > 0) {
|
||||||
|
|
@ -326,6 +331,23 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} iff the content is compressed.
|
||||||
|
*
|
||||||
|
* <p>If {@code true}, clients cannot use the value of content length from the request headers to
|
||||||
|
* read the data, since Cronet returns the uncompressed data and this content length reflects the
|
||||||
|
* compressed content length.
|
||||||
|
*/
|
||||||
|
private boolean isCompressed(UrlResponseInfo info) {
|
||||||
|
for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) {
|
||||||
|
if (entry.getKey().equalsIgnoreCase("Content-Encoding")) {
|
||||||
|
return !entry.getValue().equalsIgnoreCase("identity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void validateResponse(UrlResponseInfo info) throws HttpDataSourceException {
|
private void validateResponse(UrlResponseInfo info) throws HttpDataSourceException {
|
||||||
// Check for a valid response code.
|
// Check for a valid response code.
|
||||||
int responseCode = info.getHttpStatusCode();
|
int responseCode = info.getHttpStatusCode();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue