Follow 307/308 POST redirects for license requests

I was considering putting this directly in DefaultHttpDataSource, however:

- We'd need to modify at least OkHttpDataSource as well. I'm not sure whether
  Cronet follows this type of redirect automatically or not.
- HttpDataSource instances don't know how they're going to be used, so it's
  probably correct that they behave like the underlying network stack.

Issue: #4108

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=192745408
This commit is contained in:
olly 2018-04-13 03:25:04 -07:00 committed by Oliver Woodman
parent 22b8ab5c09
commit 0ee3963789
2 changed files with 47 additions and 9 deletions

View file

@ -51,13 +51,15 @@
* Add release method to Cache interface.
* Prevent multiple instances of SimpleCache in the same folder.
Previous instance must be released.
* Store redirected URI
([#2360](https://github.com/google/ExoPlayer/issues/2360)).
* Cache redirect URLs
([#2360](https://github.com/google/ExoPlayer/issues/2360)).
* DRM:
* Allow multiple listeners for `DefaultDrmSessionManager`.
* Pass `DrmSessionManager` to `ExoPlayerFactory` instead of `RendererFactory`.
* Change minimum API requirement for CBC and pattern encryption from 24 to 25
([#4022][https://github.com/google/ExoPlayer/issues/4022]).
* Fix handling of 307/308 redirects when making license requests
([#4108](https://github.com/google/ExoPlayer/issues/4108)).
* Removed default renderer time offset of 60000000 from internal player. The
actual renderer timestamp offset can be obtained by listening to
`BaseRenderer.onStreamChanged`.

View file

@ -24,10 +24,12 @@ import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -37,6 +39,8 @@ import java.util.UUID;
@TargetApi(18)
public final class HttpMediaDrmCallback implements MediaDrmCallback {
private static final int MAX_MANUAL_REDIRECTS = 5;
private final HttpDataSource.Factory dataSourceFactory;
private final String defaultLicenseUrl;
private final boolean forceDefaultLicenseUrl;
@ -138,14 +142,46 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
dataSource.setRequestProperty(requestProperty.getKey(), requestProperty.getValue());
}
}
DataSpec dataSpec = new DataSpec(Uri.parse(url), data, 0, 0, C.LENGTH_UNSET, null,
DataSpec.FLAG_ALLOW_GZIP);
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
return Util.toByteArray(inputStream);
} finally {
Util.closeQuietly(inputStream);
int manualRedirectCount = 0;
while (true) {
DataSpec dataSpec =
new DataSpec(
Uri.parse(url),
data,
/* absoluteStreamPosition= */ 0,
/* position= */ 0,
/* length= */ C.LENGTH_UNSET,
/* key= */ null,
DataSpec.FLAG_ALLOW_GZIP);
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
return Util.toByteArray(inputStream);
} catch (InvalidResponseCodeException e) {
// For POST requests, the underlying network stack will not normally follow 307 or 308
// redirects automatically. Do so manually here.
boolean manuallyRedirect =
(e.responseCode == 307 || e.responseCode == 308)
&& manualRedirectCount++ < MAX_MANUAL_REDIRECTS;
url = manuallyRedirect ? getRedirectUrl(e) : null;
if (url == null) {
throw e;
}
} finally {
Util.closeQuietly(inputStream);
}
}
}
private static String getRedirectUrl(InvalidResponseCodeException exception) {
Map<String, List<String>> headerFields = exception.headerFields;
if (headerFields != null) {
List<String> locationHeaders = headerFields.get("Location");
if (locationHeaders != null && !locationHeaders.isEmpty()) {
return locationHeaders.get(0);
}
}
return null;
}
}