From 0ee39637896485bb4319b5dfd865026def4518a2 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 13 Apr 2018 03:25:04 -0700 Subject: [PATCH] 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 --- RELEASENOTES.md | 6 ++- .../exoplayer2/drm/HttpMediaDrmCallback.java | 50 ++++++++++++++++--- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d7ece8f5563..f0c34ba5cc0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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`. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java index dfbf3dee07d..4a93ac83335 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java @@ -24,10 +24,12 @@ 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 @@ @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 @@ private static byte[] executePost(HttpDataSource.Factory dataSourceFactory, Stri 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> headerFields = exception.headerFields; + if (headerFields != null) { + List locationHeaders = headerFields.get("Location"); + if (locationHeaders != null && !locationHeaders.isEmpty()) { + return locationHeaders.get(0); + } } + return null; } }