diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index e32e063d0c..3563078c87 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -24,6 +24,9 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; /** * Defines a region of data. @@ -102,9 +105,10 @@ public final class DataSpec { /** @deprecated Use {@link #httpBody} instead. */ @Deprecated public final @Nullable byte[] postBody; - /** - * The absolute position of the data in the full stream. - */ + /** Immutable map containing the headers to use in HTTP requests. */ + public final Map httpRequestHeaders; + + /** The absolute position of the data in the full stream. */ public final long absoluteStreamPosition; /** * The position of the data when read from {@link #uri}. @@ -235,7 +239,6 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ - @SuppressWarnings("deprecation") public DataSpec( Uri uri, @HttpMethod int httpMethod, @@ -245,6 +248,41 @@ public final class DataSpec { long length, @Nullable String key, @Flags int flags) { + this( + uri, + httpMethod, + httpBody, + absoluteStreamPosition, + position, + length, + key, + flags, + /* httpRequestHeaders= */ Collections.emptyMap()); + } + + /** + * Construct a data spec with request parameters to be used as HTTP headers inside HTTP requests. + * + * @param uri {@link #uri}. + * @param httpMethod {@link #httpMethod}. + * @param httpBody {@link #httpBody}. + * @param absoluteStreamPosition {@link #absoluteStreamPosition}. + * @param position {@link #position}. + * @param length {@link #length}. + * @param key {@link #key}. + * @param flags {@link #flags}. + * @param httpRequestHeaders {@link #httpRequestHeaders}. + */ + public DataSpec( + Uri uri, + @HttpMethod int httpMethod, + @Nullable byte[] httpBody, + long absoluteStreamPosition, + long position, + long length, + @Nullable String key, + @Flags int flags, + Map httpRequestHeaders) { Assertions.checkArgument(absoluteStreamPosition >= 0); Assertions.checkArgument(position >= 0); Assertions.checkArgument(length > 0 || length == C.LENGTH_UNSET); @@ -257,6 +295,7 @@ public final class DataSpec { this.length = length; this.key = key; this.flags = flags; + this.httpRequestHeaders = Collections.unmodifiableMap(new HashMap<>(httpRequestHeaders)); } /** @@ -344,7 +383,8 @@ public final class DataSpec { position + offset, length, key, - flags); + flags, + httpRequestHeaders); } } @@ -356,6 +396,14 @@ public final class DataSpec { */ public DataSpec withUri(Uri uri) { return new DataSpec( - uri, httpMethod, httpBody, absoluteStreamPosition, position, length, key, flags); + uri, + httpMethod, + httpBody, + absoluteStreamPosition, + position, + length, + key, + flags, + httpRequestHeaders); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java new file mode 100644 index 0000000000..f6e30f814a --- /dev/null +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java @@ -0,0 +1,128 @@ +/* + * 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 static junit.framework.TestCase.fail; + +import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Unit tests for {@link DataSpec}. */ +@RunWith(AndroidJUnit4.class) +public class DataSpecTest { + + @Test + public void createDataSpec_withDefaultValues_setsEmptyHttpRequestParameters() { + Uri uri = Uri.parse("www.google.com"); + DataSpec dataSpec = new DataSpec(uri); + + assertThat(dataSpec.httpRequestHeaders.isEmpty()).isTrue(); + + dataSpec = new DataSpec(uri, /*flags= */ 0); + assertThat(dataSpec.httpRequestHeaders.isEmpty()).isTrue(); + + dataSpec = + new DataSpec( + uri, + /* httpMethod= */ 0, + /* httpBody= */ new byte[] {0, 0, 0, 0}, + /* absoluteStreamPosition= */ 0, + /* position= */ 0, + /* length= */ 1, + /* key= */ "key", + /* flags= */ 0); + assertThat(dataSpec.httpRequestHeaders.isEmpty()).isTrue(); + } + + @Test + public void createDataSpec_setsHttpRequestParameters() { + Map httpRequestParameters = new HashMap<>(); + httpRequestParameters.put("key1", "value1"); + httpRequestParameters.put("key2", "value2"); + httpRequestParameters.put("key3", "value3"); + + DataSpec dataSpec = + new DataSpec( + Uri.parse("www.google.com"), + /* httpMethod= */ 0, + /* httpBody= */ new byte[] {0, 0, 0, 0}, + /* absoluteStreamPosition= */ 0, + /* position= */ 0, + /* length= */ 1, + /* key= */ "key", + /* flags= */ 0, + httpRequestParameters); + + assertThat(dataSpec.httpRequestHeaders).isEqualTo(httpRequestParameters); + } + + @Test + public void httpRequestParameters_areReadOnly() { + DataSpec dataSpec = + new DataSpec( + Uri.parse("www.google.com"), + /* httpMethod= */ 0, + /* httpBody= */ new byte[] {0, 0, 0, 0}, + /* absoluteStreamPosition= */ 0, + /* position= */ 0, + /* length= */ 1, + /* key= */ "key", + /* flags= */ 0, + /* httpRequestHeaders= */ new HashMap<>()); + + try { + dataSpec.httpRequestHeaders.put("key", "value"); + fail(); + } catch (UnsupportedOperationException expected) { + // Expected + } + } + + @Test + public void copyMethods_copiesHttpRequestHeaders() { + Map httpRequestParameters = new HashMap<>(); + httpRequestParameters.put("key1", "value1"); + httpRequestParameters.put("key2", "value2"); + httpRequestParameters.put("key3", "value3"); + + DataSpec dataSpec = + new DataSpec( + Uri.parse("www.google.com"), + /* httpMethod= */ 0, + /* httpBody= */ new byte[] {0, 0, 0, 0}, + /* absoluteStreamPosition= */ 0, + /* position= */ 0, + /* length= */ 1, + /* key= */ "key", + /* flags= */ 0, + httpRequestParameters); + + DataSpec dataSpecCopy = dataSpec.withUri(Uri.parse("www.new-uri.com")); + assertThat(dataSpecCopy.httpRequestHeaders).isEqualTo(httpRequestParameters); + + dataSpecCopy = dataSpec.subrange(2); + assertThat(dataSpecCopy.httpRequestHeaders).isEqualTo(httpRequestParameters); + + dataSpecCopy = dataSpec.subrange(2, 2); + assertThat(dataSpecCopy.httpRequestHeaders).isEqualTo(httpRequestParameters); + } +}