Skip to content

Commit

Permalink
Add gzip support to WebServerDispatcher
Browse files Browse the repository at this point in the history
Add a test to DataSourceContractTest that asserts the gzip flag is
either ignored or handled correctly.

Add a test resource to DefaultHttpDataSourceContracTest that enables
gzip compression on the 'server' and checks it's handled correctly by
the client.

PiperOrigin-RevId: 352574359
  • Loading branch information
icbaker authored and ojw28 committed Jan 19, 2021
1 parent dd1b1c0 commit 3069251
Show file tree
Hide file tree
Showing 7 changed files with 466 additions and 9 deletions.
1 change: 1 addition & 0 deletions library/common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies {
testImplementation 'junit:junit:' + junitVersion
testImplementation 'com.google.truth:truth:' + truthVersion
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
testImplementation project(modulePrefix + 'testutils')
}

ext {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DataFormatException;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.compatqual.NullableType;
Expand Down Expand Up @@ -2121,6 +2122,17 @@ public static int crc8(byte[] bytes, int start, int end, int initialValue) {
return initialValue;
}

/** Compresses {@code input} using gzip and returns the result in a newly allocated byte array. */
public static byte[] gzip(byte[] input) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (GZIPOutputStream os = new GZIPOutputStream(output)) {
os.write(input);
} catch (IOException e) {
throw new AssertionError(e);
}
return output.toByteArray();
}

/**
* Absolute <i>get</i> method for reading an int value in {@link ByteOrder#BIG_ENDIAN} in a {@link
* ByteBuffer}. Same as {@link ByteBuffer#getInt(int)} except the buffer's order as returned by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.android.exoplayer2.util.Util.escapeFileName;
import static com.google.android.exoplayer2.util.Util.getCodecsOfType;
import static com.google.android.exoplayer2.util.Util.getStringForTime;
import static com.google.android.exoplayer2.util.Util.gzip;
import static com.google.android.exoplayer2.util.Util.minValue;
import static com.google.android.exoplayer2.util.Util.parseXsDateTime;
import static com.google.android.exoplayer2.util.Util.parseXsDuration;
Expand All @@ -37,6 +38,9 @@
import android.util.SparseLongArray;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.common.io.ByteStreams;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
Expand All @@ -45,6 +49,7 @@
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
Expand Down Expand Up @@ -927,6 +932,17 @@ public void crc8_returnsUpdatedCrc8() {
assertThat(result).isEqualTo(0x4);
}

@Test
public void gzip_resultInflatesBackToOriginalValue() throws Exception {
byte[] input = TestUtil.buildTestData(20);

byte[] deflated = gzip(input);

byte[] inflated =
ByteStreams.toByteArray(new GZIPInputStream(new ByteArrayInputStream(deflated)));
assertThat(inflated).isEqualTo(input);
}

@Test
public void getBigEndianInt_fromBigEndian() {
byte[] bytes = {0x1F, 0x2E, 0x3D, 0x4C};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,43 @@ public void dataSpecWithPositionAndLength_readExpectedRange() throws Exception {
}
}

/**
* {@link DataSpec#FLAG_ALLOW_GZIP} should either be ignored by {@link DataSource}
* implementations, or correctly handled (i.e. the data is decompressed before being returned from
* {@link DataSource#read(byte[], int, int)}).
*/
@Test
public void gzipFlagDoesntAffectReturnedData() throws Exception {
ImmutableList<TestResource> resources = getTestResources();
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");

for (int i = 0; i < resources.size(); i++) {
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
TestResource resource = resources.get(i);
DataSource dataSource = createDataSource();
try {
long length =
dataSource.open(
new DataSpec.Builder()
.setUri(resource.getUri())
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
.build());
byte[] data =
resource.isEndOfInputExpected()
? Util.readToEnd(dataSource)
: Util.readExactly(dataSource, resource.getExpectedBytes().length);

if (length != C.LENGTH_UNSET) {
assertThat(length).isEqualTo(resource.getExpectedBytes().length);
}
assertThat(data).isEqualTo(resource.getExpectedBytes());
} finally {
dataSource.close();
}
additionalFailureInfo.setInfo(null);
}
}

@Test
public void resourceNotFound() throws Exception {
DataSource dataSource = createDataSource();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ public class HttpDataSourceTestEnv extends ExternalResource {
.resolvesToUnknownLength(true)
.build();

private static final WebServerDispatcher.Resource GZIP_ENABLED =
new WebServerDispatcher.Resource.Builder()
.setPath("/gzip/enabled")
.setData(TestUtil.buildTestData(/* length= */ 20, seed++))
.setGzipSupport(WebServerDispatcher.Resource.GZIP_SUPPORT_ENABLED)
.build();

private static final WebServerDispatcher.Resource GZIP_FORCED =
new WebServerDispatcher.Resource.Builder()
.setPath("/gzip/forced")
.setData(TestUtil.buildTestData(/* length= */ 20, seed++))
.setGzipSupport(WebServerDispatcher.Resource.GZIP_SUPPORT_FORCED)
.build();

private static final WebServerDispatcher.Resource REDIRECTS_TO_RANGE_SUPPORTED =
RANGE_SUPPORTED.buildUpon().setPath("/redirects/to/range/supported").build();

Expand All @@ -74,6 +88,8 @@ public ImmutableList<DataSourceContractTest.TestResource> getServedResources() {
createTestResource("range not supported", RANGE_NOT_SUPPORTED),
createTestResource(
"range not supported, length unknown", RANGE_NOT_SUPPORTED_LENGTH_UNKNOWN),
createTestResource("gzip enabled", GZIP_ENABLED),
createTestResource("gzip forced", GZIP_FORCED),
createTestResource(
"302 redirect", REDIRECTS_TO_RANGE_SUPPORTED, /* server= */ redirectionServer));
}
Expand All @@ -91,7 +107,9 @@ protected void before() throws Throwable {
RANGE_SUPPORTED,
RANGE_SUPPORTED_LENGTH_UNKNOWN,
RANGE_NOT_SUPPORTED,
RANGE_NOT_SUPPORTED_LENGTH_UNKNOWN)));
RANGE_NOT_SUPPORTED_LENGTH_UNKNOWN,
GZIP_ENABLED,
GZIP_FORCED)));

redirectionServer.start();
redirectionServer.setDispatcher(
Expand Down
Loading

0 comments on commit 3069251

Please sign in to comment.