From 6acf59c4fc12bfca9c77bdea3f69cf3b33d66d45 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 13 Oct 2016 08:23:39 -0700 Subject: [PATCH] Fix Widevine L3 provisioning in V2 1. HttpMediaDrmCallback.executeProvisionRequest needs to specify an empty byte[], else we do a GET instead of a POST. 2. Content-Type should not be set when making the provision request, since there's no body. 3. DataSource implementations must correctly handle a non-null body with zero length. CronetDataSource was not handling this case. DefaultHttpDataSource was, but made a code modification to make it a little clearer. OkHttpDataSource seems to handle the case correctly, and it doens't look like the code can be made clearer. Issue #1925 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=136042641 --- .../exoplayer2/ext/cronet/CronetDataSource.java | 15 ++++++++++----- .../exoplayer2/drm/HttpMediaDrmCallback.java | 5 ++--- .../upstream/DefaultHttpDataSource.java | 15 ++++++++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index 15ffe5f141d..0190668a70a 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -416,8 +416,10 @@ private UrlRequest buildRequest(DataSpec dataSpec) throws OpenException { executor, cronetEngine); // Set the headers. synchronized (requestProperties) { - if (dataSpec.postBody != null && !requestProperties.containsKey(CONTENT_TYPE)) { - throw new OpenException("POST request must set Content-Type", dataSpec, Status.IDLE); + if (dataSpec.postBody != null && dataSpec.postBody.length != 0 + && !requestProperties.containsKey(CONTENT_TYPE)) { + throw new OpenException("POST request with non-empty body must set Content-Type", dataSpec, + Status.IDLE); } for (Entry headerEntry : requestProperties.entrySet()) { requestBuilder.addHeader(headerEntry.getKey(), headerEntry.getValue()); @@ -434,10 +436,13 @@ private UrlRequest buildRequest(DataSpec dataSpec) throws OpenException { } requestBuilder.addHeader("Range", rangeValue.toString()); } - // Set the body. + // Set the method and (if non-empty) the body. if (dataSpec.postBody != null) { - requestBuilder.setUploadDataProvider(new ByteArrayUploadDataProvider(dataSpec.postBody), - executor); + requestBuilder.setHttpMethod("POST"); + if (dataSpec.postBody.length != 0) { + requestBuilder.setUploadDataProvider(new ByteArrayUploadDataProvider(dataSpec.postBody), + executor); + } } return requestBuilder.build(); } diff --git a/library/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java b/library/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java index 14329d47ee1..65e41dd91e0 100644 --- a/library/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java +++ b/library/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java @@ -71,7 +71,7 @@ public HttpMediaDrmCallback(String defaultUrl, HttpDataSource.Factory dataSource @Override public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException { String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); - return executePost(url, null, null); + return executePost(url, new byte[0], null); } @Override @@ -81,6 +81,7 @@ public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception url = defaultUrl; } Map requestProperties = new HashMap<>(); + requestProperties.put("Content-Type", "application/octet-stream"); if (C.PLAYREADY_UUID.equals(uuid)) { requestProperties.putAll(PLAYREADY_KEY_REQUEST_PROPERTIES); } @@ -93,8 +94,6 @@ public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception private byte[] executePost(String url, byte[] data, Map requestProperties) throws IOException { HttpDataSource dataSource = dataSourceFactory.createDataSource(); - // Note: This will be overridden by a Content-Type in requestProperties, if one is set. - dataSource.setRequestProperty("Content-Type", "application/octet-stream"); if (requestProperties != null) { for (Map.Entry requestProperty : requestProperties.entrySet()) { dataSource.setRequestProperty(requestProperty.getKey(), requestProperty.getValue()); diff --git a/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java b/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java index 34ec76b6739..b326c41b18e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java @@ -413,11 +413,16 @@ private HttpURLConnection makeConnection(URL url, byte[] postBody, long position connection.setInstanceFollowRedirects(followRedirects); connection.setDoOutput(postBody != null); if (postBody != null) { - connection.setFixedLengthStreamingMode(postBody.length); - connection.connect(); - OutputStream os = connection.getOutputStream(); - os.write(postBody); - os.close(); + connection.setRequestMethod("POST"); + if (postBody.length == 0) { + connection.connect(); + } else { + connection.setFixedLengthStreamingMode(postBody.length); + connection.connect(); + OutputStream os = connection.getOutputStream(); + os.write(postBody); + os.close(); + } } else { connection.connect(); }