Propagate HTTP request headers through CacheDataSource

This has been broken since
c3d6be3afd
and broken for ICY (where I noticed the problem) since
5695bae9d8.
ICY symptom is that we see no repeated metadata, because the
Icy-MetaData:1 header doesn't make it to the server so we never get back
icy-metaint.

PiperOrigin-RevId: 285379234
This commit is contained in:
ibaker 2019-12-13 13:02:58 +00:00 committed by Ian Baker
parent a39e6790c9
commit 412db2008b
3 changed files with 61 additions and 7 deletions

View File

@ -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) ###

View File

@ -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<String, String> 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 {

View File

@ -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<String, String> 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);
}
}