Commit 967abdf0 by christosts Committed by Oliver Woodman

Use DataSpec request params in DefaultHttpDataSource

DefaultHttpDataSource.open() also includes the request parameters that
are inside the DataSpec.

PiperOrigin-RevId: 266350573
parent 95081468
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.metadata.icy.IcyHeaders;
......@@ -36,6 +37,7 @@ import java.net.NoRouteToHostException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
......@@ -53,9 +55,7 @@ import java.util.zip.GZIPInputStream;
*/
public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSource {
/**
* The default connection timeout, in milliseconds.
*/
/** The default connection timeout, in milliseconds. */
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 8 * 1000;
/**
* The default read timeout, in milliseconds.
......@@ -263,6 +263,13 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
requestProperties.clear();
}
/**
* Opens the source to read the specified data.
*
* <p>Note: HTTP request headers will be set using parameters passed via (in order of decreasing
* priority) the {@code dataSpec}, {@link #setRequestProperty} and the default parameters used to
* construct the instance.
*/
@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
this.dataSpec = dataSpec;
......@@ -374,6 +381,13 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
}
}
/** Creates an {@link HttpURLConnection} that is connected with the {@code url}. */
@VisibleForTesting
/* package */
HttpURLConnection openConnection(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
/**
* Returns the current connection, or null if the source is not currently opened.
*
......@@ -438,7 +452,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
length,
allowGzip,
allowIcyMetadata,
/* followRedirects= */ true);
/* followRedirects= */ true,
dataSpec.httpRequestHeaders);
}
// We need to handle redirects ourselves to allow cross-protocol redirects.
......@@ -453,7 +468,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
length,
allowGzip,
allowIcyMetadata,
/* followRedirects= */ false);
/* followRedirects= */ false,
dataSpec.httpRequestHeaders);
int responseCode = connection.getResponseCode();
String location = connection.getHeaderField("Location");
if ((httpMethod == DataSpec.HTTP_METHOD_GET || httpMethod == DataSpec.HTTP_METHOD_HEAD)
......@@ -495,6 +511,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
* @param allowGzip Whether to allow the use of gzip.
* @param allowIcyMetadata Whether to allow ICY metadata.
* @param followRedirects Whether to follow redirects.
* @param requestParameters parameters (HTTP headers) to include in request.
*/
private HttpURLConnection makeConnection(
URL url,
......@@ -504,19 +521,24 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
long length,
boolean allowGzip,
boolean allowIcyMetadata,
boolean followRedirects)
boolean followRedirects,
Map<String, String> requestParameters)
throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
HttpURLConnection connection = openConnection(url);
connection.setConnectTimeout(connectTimeoutMillis);
connection.setReadTimeout(readTimeoutMillis);
Map<String, String> requestHeaders = new HashMap<>();
if (defaultRequestProperties != null) {
for (Map.Entry<String, String> property : defaultRequestProperties.getSnapshot().entrySet()) {
connection.setRequestProperty(property.getKey(), property.getValue());
}
requestHeaders.putAll(defaultRequestProperties.getSnapshot());
}
for (Map.Entry<String, String> property : requestProperties.getSnapshot().entrySet()) {
requestHeaders.putAll(requestProperties.getSnapshot());
requestHeaders.putAll(requestParameters);
for (Map.Entry<String, String> property : requestHeaders.entrySet()) {
connection.setRequestProperty(property.getKey(), property.getValue());
}
if (!(position == 0 && length == C.LENGTH_UNSET)) {
String rangeRequest = "bytes=" + position + "-";
if (length != C.LENGTH_UNSET) {
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
/** Unit tests for {@link DefaultHttpDataSource}. */
@RunWith(AndroidJUnit4.class)
public class DefaultHttpDataSourceTest {
@Test
public void open_withSpecifiedRequestParameters_usesCorrectParameters() throws IOException {
/*
* This test will set HTTP request parameters in the HttpDataSourceFactory (default),
* in the DefaultHttpDataSource instance and in the DataSpec instance according to the table
* below. Values wrapped in '*' are the ones that should be set in the connection request.
*
* +-----------------------+---+-----+-----+-----+-----+-----+
* | | Header Key |
* +-----------------------+---+-----+-----+-----+-----+-----+
* | Location | 0 | 1 | 2 | 3 | 4 | 5 |
* +-----------------------+---+-----+-----+-----+-----+-----+
* | Default |*Y*| Y | Y | | | |
* | DefaultHttpDataSource | | *Y* | Y | Y | *Y* | |
* | DataSpec | | | *Y* | *Y* | | *Y* |
* +-----------------------+---+-----+-----+-----+-----+-----+
*/
String defaultParameter = "Default";
String dataSourceInstanceParameter = "DefaultHttpDataSource";
String dataSpecParameter = "Dataspec";
HttpDataSource.RequestProperties defaultParameters = new HttpDataSource.RequestProperties();
defaultParameters.set("0", defaultParameter);
defaultParameters.set("1", defaultParameter);
defaultParameters.set("2", defaultParameter);
DefaultHttpDataSource defaultHttpDataSource =
Mockito.spy(
new DefaultHttpDataSource(
/* userAgent= */ "testAgent",
/* connectTimeoutMillis= */ 1000,
/* readTimeoutMillis= */ 1000,
/* allowCrossProtocolRedirects= */ false,
defaultParameters));
Map<String, String> sentRequestProperties = new HashMap<>();
HttpURLConnection mockHttpUrlConnection = makeMockHttpUrlConnection(sentRequestProperties);
Mockito.doReturn(mockHttpUrlConnection)
.when(defaultHttpDataSource)
.openConnection(ArgumentMatchers.any());
defaultHttpDataSource.setRequestProperty("1", dataSourceInstanceParameter);
defaultHttpDataSource.setRequestProperty("2", dataSourceInstanceParameter);
defaultHttpDataSource.setRequestProperty("3", dataSourceInstanceParameter);
defaultHttpDataSource.setRequestProperty("4", dataSourceInstanceParameter);
Map<String, String> dataSpecRequestProperties = new HashMap<>();
dataSpecRequestProperties.put("2", dataSpecParameter);
dataSpecRequestProperties.put("3", dataSpecParameter);
dataSpecRequestProperties.put("5", dataSpecParameter);
DataSpec dataSpec =
new DataSpec(
/* uri= */ Uri.parse("http://www.google.com"),
/* httpMethod= */ 1,
/* httpBody= */ new byte[] {0, 0, 0, 0},
/* absoluteStreamPosition= */ 0,
/* position= */ 0,
/* length= */ 1,
/* key= */ "key",
/* flags= */ 0,
dataSpecRequestProperties);
defaultHttpDataSource.open(dataSpec);
assertThat(sentRequestProperties.get("0")).isEqualTo(defaultParameter);
assertThat(sentRequestProperties.get("1")).isEqualTo(dataSourceInstanceParameter);
assertThat(sentRequestProperties.get("2")).isEqualTo(dataSpecParameter);
assertThat(sentRequestProperties.get("3")).isEqualTo(dataSpecParameter);
assertThat(sentRequestProperties.get("4")).isEqualTo(dataSourceInstanceParameter);
assertThat(sentRequestProperties.get("5")).isEqualTo(dataSpecParameter);
}
/**
* Creates a mock {@link HttpURLConnection} that stores all request parameters inside {@code
* requestProperties}.
*/
private static HttpURLConnection makeMockHttpUrlConnection(Map<String, String> requestProperties)
throws IOException {
HttpURLConnection mockHttpUrlConnection = Mockito.mock(HttpURLConnection.class);
Mockito.when(mockHttpUrlConnection.usingProxy()).thenReturn(false);
Mockito.when(mockHttpUrlConnection.getInputStream())
.thenReturn(new ByteArrayInputStream(new byte[128]));
Mockito.when(mockHttpUrlConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
Mockito.when(mockHttpUrlConnection.getResponseCode()).thenReturn(200);
Mockito.when(mockHttpUrlConnection.getResponseMessage()).thenReturn("OK");
Mockito.doAnswer(
(invocation) -> {
String key = invocation.getArgument(0);
String value = invocation.getArgument(1);
requestProperties.put(key, value);
return null;
})
.when(mockHttpUrlConnection)
.setRequestProperty(ArgumentMatchers.anyString(), ArgumentMatchers.anyString());
return mockHttpUrlConnection;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment