diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c1369a5297..619807c90a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -25,6 +25,7 @@ [Span-styled text]( https://developer.android.com/guide/topics/text/spans) (e.g. subtitles). * Add `Player.getCurrentLiveOffset` to conveniently return the live offset. +* Propagate HTTP request headers through `CacheDataSource`. ### 2.11.0 (2019-12-11) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java index c51f75116f..502a22acfa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java @@ -138,7 +138,8 @@ public final class CacheDataSource implements DataSource { @Nullable private Uri actualUri; @HttpMethod private int httpMethod; @Nullable private byte[] httpBody; - private int flags; + private Map httpRequestHeaders = Collections.emptyMap(); + @DataSpec.Flags private int flags; @Nullable private String key; private long readPosition; private long bytesRemaining; @@ -263,6 +264,7 @@ public final class CacheDataSource implements DataSource { actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri); httpMethod = dataSpec.httpMethod; httpBody = dataSpec.httpBody; + httpRequestHeaders = dataSpec.httpRequestHeaders; flags = dataSpec.flags; readPosition = dataSpec.position; @@ -353,6 +355,10 @@ public final class CacheDataSource implements DataSource { actualUri = null; httpMethod = DataSpec.HTTP_METHOD_GET; httpBody = null; + httpRequestHeaders = Collections.emptyMap(); + flags = 0; + readPosition = 0; + key = null; notifyBytesRead(); try { closeCurrentSource(); @@ -399,7 +405,15 @@ public final class CacheDataSource implements DataSource { nextDataSource = upstreamDataSource; nextDataSpec = new DataSpec( - uri, httpMethod, httpBody, readPosition, readPosition, bytesRemaining, key, flags); + uri, + httpMethod, + httpBody, + readPosition, + readPosition, + bytesRemaining, + key, + flags, + httpRequestHeaders); } else if (nextSpan.isCached) { // Data is cached, read from cache. Uri fileUri = Uri.fromFile(nextSpan.file); @@ -408,6 +422,8 @@ public final class CacheDataSource implements DataSource { if (bytesRemaining != C.LENGTH_UNSET) { length = Math.min(length, bytesRemaining); } + // Deliberately skip the HTTP-related parameters since we're reading from the cache, not + // making an HTTP request. nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags); nextDataSource = cacheReadDataSource; } else { @@ -422,7 +438,16 @@ public final class CacheDataSource implements DataSource { } } nextDataSpec = - new DataSpec(uri, httpMethod, httpBody, readPosition, readPosition, length, key, flags); + new DataSpec( + uri, + httpMethod, + httpBody, + readPosition, + readPosition, + length, + key, + flags, + httpRequestHeaders); if (cacheWriteDataSource != null) { nextDataSource = cacheWriteDataSource; } else { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 83104119ad..27438fcac3 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -34,6 +34,8 @@ import com.google.android.exoplayer2.util.Util; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.NavigableSet; import org.junit.After; import org.junit.Before; @@ -48,20 +50,27 @@ public final class CacheDataSourceTest { private static final int CACHE_FRAGMENT_SIZE = 3; private static final String DATASPEC_KEY = "dataSpecKey"; + // Test data private Uri testDataUri; + private Map httpRequestHeaders; private DataSpec unboundedDataSpec; private DataSpec boundedDataSpec; private DataSpec unboundedDataSpecWithKey; private DataSpec boundedDataSpecWithKey; private String defaultCacheKey; private String customCacheKey; + + // Dependencies of SUT private CacheKeyFactory cacheKeyFactory; private File tempFolder; private SimpleCache cache; + private FakeDataSource upstreamDataSource; @Before public void setUp() throws Exception { testDataUri = Uri.parse("https://www.test.com/data"); + httpRequestHeaders = new HashMap<>(); + httpRequestHeaders.put("Test-key", "Test-val"); unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null); boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null); unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY); @@ -69,9 +78,11 @@ public final class CacheDataSourceTest { defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec); customCacheKey = "customKey." + defaultCacheKey; cacheKeyFactory = dataSpec -> customCacheKey; + tempFolder = Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest"); cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); + upstreamDataSource = new FakeDataSource(); } @After @@ -111,6 +122,19 @@ public final class CacheDataSourceTest { assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false); } + @Test + public void testPropagatesHttpHeadersUpstream() throws Exception { + CacheDataSource cacheDataSource = + createCacheDataSource(/* setReadException= */ false, /* unknownLength= */ false); + DataSpec dataSpec = buildDataSpec(/* position= */ 2, /* length= */ 5); + cacheDataSource.open(dataSpec); + + DataSpec[] upstreamDataSpecs = upstreamDataSource.getAndClearOpenedDataSpecs(); + + assertThat(upstreamDataSpecs).hasLength(1); + assertThat(upstreamDataSpecs[0].httpRequestHeaders).isEqualTo(this.httpRequestHeaders); + } + @Test public void testUnsatisfiableRange() throws Exception { // Bounded request but the content length is unknown. This forces all data to be cached but not @@ -572,9 +596,8 @@ public final class CacheDataSourceTest { @CacheDataSource.Flags int flags, CacheDataSink cacheWriteDataSink, CacheKeyFactory cacheKeyFactory) { - FakeDataSource upstream = new FakeDataSource(); FakeData fakeData = - upstream + upstreamDataSource .getDataSet() .newDefaultData() .setSimulateUnknownLength(unknownLength) @@ -584,7 +607,7 @@ public final class CacheDataSourceTest { } return new CacheDataSource( cache, - upstream, + upstreamDataSource, new FileDataSource(), cacheWriteDataSink, flags, @@ -602,6 +625,11 @@ public final class CacheDataSourceTest { private DataSpec buildDataSpec(long position, long length, @Nullable String key) { return new DataSpec( - testDataUri, position, length, key, DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION); + testDataUri, + position, + length, + key, + DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION, + httpRequestHeaders); } }