1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.upstream; 17 18 import android.net.Uri; 19 import androidx.annotation.IntDef; 20 import androidx.annotation.Nullable; 21 import com.google.android.exoplayer2.C; 22 import com.google.android.exoplayer2.util.Assertions; 23 import java.lang.annotation.Documented; 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.util.Collections; 27 import java.util.HashMap; 28 import java.util.Map; 29 30 /** 31 * Defines a region of data. 32 */ 33 public final class DataSpec { 34 35 /** 36 * Builds {@link DataSpec} instances. 37 * 38 * <p>Use DataSpec#buildUpon() to obtain a builder representing an existing {@link DataSpec}. 39 */ 40 public static final class Builder { 41 42 @Nullable private Uri uri; 43 private long uriPositionOffset; 44 @HttpMethod private int httpMethod; 45 @Nullable private byte[] httpBody; 46 private Map<String, String> httpRequestHeaders; 47 private long position; 48 private long length; 49 @Nullable private String key; 50 @Flags private int flags; 51 @Nullable private Object customData; 52 53 /** Creates a new instance with default values. */ Builder()54 public Builder() { 55 httpMethod = HTTP_METHOD_GET; 56 httpRequestHeaders = Collections.emptyMap(); 57 length = C.LENGTH_UNSET; 58 } 59 60 /** 61 * Creates a new instance to build upon the provided {@link DataSpec}. 62 * 63 * @param dataSpec The {@link DataSpec} to build upon. 64 */ Builder(DataSpec dataSpec)65 private Builder(DataSpec dataSpec) { 66 uri = dataSpec.uri; 67 uriPositionOffset = dataSpec.uriPositionOffset; 68 httpMethod = dataSpec.httpMethod; 69 httpBody = dataSpec.httpBody; 70 httpRequestHeaders = dataSpec.httpRequestHeaders; 71 position = dataSpec.position; 72 length = dataSpec.length; 73 key = dataSpec.key; 74 flags = dataSpec.flags; 75 customData = dataSpec.customData; 76 } 77 78 /** 79 * Sets {@link DataSpec#uri}. 80 * 81 * @param uriString The {@link DataSpec#uri}. 82 * @return The builder. 83 */ setUri(String uriString)84 public Builder setUri(String uriString) { 85 this.uri = Uri.parse(uriString); 86 return this; 87 } 88 89 /** 90 * Sets {@link DataSpec#uri}. 91 * 92 * @param uri The {@link DataSpec#uri}. 93 * @return The builder. 94 */ setUri(Uri uri)95 public Builder setUri(Uri uri) { 96 this.uri = uri; 97 return this; 98 } 99 100 /** 101 * Sets the {@link DataSpec#uriPositionOffset}. The default value is 0. 102 * 103 * @param uriPositionOffset The {@link DataSpec#uriPositionOffset}. 104 * @return The builder. 105 */ setUriPositionOffset(long uriPositionOffset)106 public Builder setUriPositionOffset(long uriPositionOffset) { 107 this.uriPositionOffset = uriPositionOffset; 108 return this; 109 } 110 111 /** 112 * Sets {@link DataSpec#httpMethod}. The default value is {@link #HTTP_METHOD_GET}. 113 * 114 * @param httpMethod The {@link DataSpec#httpMethod}. 115 * @return The builder. 116 */ setHttpMethod(@ttpMethod int httpMethod)117 public Builder setHttpMethod(@HttpMethod int httpMethod) { 118 this.httpMethod = httpMethod; 119 return this; 120 } 121 122 /** 123 * Sets {@link DataSpec#httpBody}. The default value is {@code null}. 124 * 125 * @param httpBody The {@link DataSpec#httpBody}. 126 * @return The builder. 127 */ setHttpBody(@ullable byte[] httpBody)128 public Builder setHttpBody(@Nullable byte[] httpBody) { 129 this.httpBody = httpBody; 130 return this; 131 } 132 133 /** 134 * Sets the {@link DataSpec#httpRequestHeaders}. The default value is an empty map. 135 * 136 * <p>Note: {@code Range}, {@code Accept-Encoding} and {@code User-Agent} should not be set with 137 * this method, since they are set directly by {@link HttpDataSource} implementations. See 138 * {@link DataSpec#httpRequestHeaders} for more details. 139 * 140 * @param httpRequestHeaders The {@link DataSpec#httpRequestHeaders}. 141 * @return The builder. 142 */ setHttpRequestHeaders(Map<String, String> httpRequestHeaders)143 public Builder setHttpRequestHeaders(Map<String, String> httpRequestHeaders) { 144 this.httpRequestHeaders = httpRequestHeaders; 145 return this; 146 } 147 148 /** 149 * Sets the {@link DataSpec#position}. The default value is 0. 150 * 151 * @param position The {@link DataSpec#position}. 152 * @return The builder. 153 */ setPosition(long position)154 public Builder setPosition(long position) { 155 this.position = position; 156 return this; 157 } 158 159 /** 160 * Sets the {@link DataSpec#length}. The default value is {@link C#LENGTH_UNSET}. 161 * 162 * @param length The {@link DataSpec#length}. 163 * @return The builder. 164 */ setLength(long length)165 public Builder setLength(long length) { 166 this.length = length; 167 return this; 168 } 169 170 /** 171 * Sets the {@link DataSpec#key}. The default value is {@code null}. 172 * 173 * @param key The {@link DataSpec#key}. 174 * @return The builder. 175 */ setKey(@ullable String key)176 public Builder setKey(@Nullable String key) { 177 this.key = key; 178 return this; 179 } 180 181 /** 182 * Sets the {@link DataSpec#flags}. The default value is 0. 183 * 184 * @param flags The {@link DataSpec#flags}. 185 * @return The builder. 186 */ setFlags(@lags int flags)187 public Builder setFlags(@Flags int flags) { 188 this.flags = flags; 189 return this; 190 } 191 192 /** 193 * Sets the {@link DataSpec#customData}. The default value is {@code null}. 194 * 195 * @param customData The {@link DataSpec#customData}. 196 * @return The builder. 197 */ setCustomData(@ullable Object customData)198 public Builder setCustomData(@Nullable Object customData) { 199 this.customData = customData; 200 return this; 201 } 202 203 /** 204 * Builds a {@link DataSpec} with the builder's current values. 205 * 206 * @return The build {@link DataSpec}. 207 * @throws IllegalStateException If {@link #setUri} has not been called. 208 */ build()209 public DataSpec build() { 210 Assertions.checkStateNotNull(uri, "The uri must be set."); 211 return new DataSpec( 212 uri, 213 uriPositionOffset, 214 httpMethod, 215 httpBody, 216 httpRequestHeaders, 217 position, 218 length, 219 key, 220 flags, 221 customData); 222 } 223 } 224 225 /** 226 * The flags that apply to any request for data. Possible flag values are {@link 227 * #FLAG_ALLOW_GZIP}, {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}, {@link 228 * #FLAG_ALLOW_CACHE_FRAGMENTATION}, and {@link #FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED}. 229 */ 230 @Documented 231 @Retention(RetentionPolicy.SOURCE) 232 @IntDef( 233 flag = true, 234 value = { 235 FLAG_ALLOW_GZIP, 236 FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN, 237 FLAG_ALLOW_CACHE_FRAGMENTATION, 238 FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED 239 }) 240 public @interface Flags {} 241 /** 242 * Allows an underlying network stack to request that the server use gzip compression. 243 * 244 * <p>Should not typically be set if the data being requested is already compressed (e.g. most 245 * audio and video requests). May be set when requesting other data. 246 * 247 * <p>When a {@link DataSource} is used to request data with this flag set, and if the {@link 248 * DataSource} does make a network request, then the value returned from {@link 249 * DataSource#open(DataSpec)} will typically be {@link C#LENGTH_UNSET}. The data read from {@link 250 * DataSource#read(byte[], int, int)} will be the decompressed data. 251 */ 252 public static final int FLAG_ALLOW_GZIP = 1; 253 /** Prevents caching if the length cannot be resolved when the {@link DataSource} is opened. */ 254 public static final int FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN = 1 << 1; 255 /** 256 * Allows fragmentation of this request into multiple cache files, meaning a cache eviction policy 257 * will be able to evict individual fragments of the data. Depending on the cache implementation, 258 * setting this flag may also enable more concurrent access to the data (e.g. reading one fragment 259 * whilst writing another). 260 */ 261 public static final int FLAG_ALLOW_CACHE_FRAGMENTATION = 1 << 2; 262 /** 263 * Indicates there are known external factors that might prevent the data from being loaded at 264 * full network speed (e.g. server throttling or unfinished live media chunks). 265 */ 266 public static final int FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED = 1 << 3; 267 268 /** 269 * HTTP methods supported by ExoPlayer {@link HttpDataSource}s. One of {@link #HTTP_METHOD_GET}, 270 * {@link #HTTP_METHOD_POST} or {@link #HTTP_METHOD_HEAD}. 271 */ 272 @Documented 273 @Retention(RetentionPolicy.SOURCE) 274 @IntDef({HTTP_METHOD_GET, HTTP_METHOD_POST, HTTP_METHOD_HEAD}) 275 public @interface HttpMethod {} 276 /** HTTP GET method. */ 277 public static final int HTTP_METHOD_GET = 1; 278 /** HTTP POST method. */ 279 public static final int HTTP_METHOD_POST = 2; 280 /** HTTP HEAD method. */ 281 public static final int HTTP_METHOD_HEAD = 3; 282 283 /** 284 * Returns an uppercase HTTP method name (e.g., "GET", "POST", "HEAD") corresponding to the given 285 * {@link HttpMethod}. 286 */ getStringForHttpMethod(@ttpMethod int httpMethod)287 public static String getStringForHttpMethod(@HttpMethod int httpMethod) { 288 switch (httpMethod) { 289 case HTTP_METHOD_GET: 290 return "GET"; 291 case HTTP_METHOD_POST: 292 return "POST"; 293 case HTTP_METHOD_HEAD: 294 return "HEAD"; 295 default: 296 // Never happens. 297 throw new IllegalStateException(); 298 } 299 } 300 301 /** The {@link Uri} from which data should be read. */ 302 public final Uri uri; 303 304 /** 305 * The offset of the data located at {@link #uri} within an original resource. 306 * 307 * <p>Equal to 0 unless {@link #uri} provides access to a subset of an original resource. As an 308 * example, consider a resource that can be requested over the network and is 1000 bytes long. If 309 * {@link #uri} points to a local file that contains just bytes [200-300], then this field will be 310 * set to {@code 200}. 311 * 312 * <p>This field can be ignored except for in specific circumstances where the absolute position 313 * in the original resource is required in a {@link DataSource} chain. One example is when a 314 * {@link DataSource} needs to decrypt the content as it's read. In this case the absolute 315 * position in the original resource is typically needed to correctly initialize the decryption 316 * algorithm. 317 */ 318 public final long uriPositionOffset; 319 320 /** 321 * The HTTP method to use when requesting the data. This value will be ignored by non-HTTP {@link 322 * DataSource} implementations. 323 */ 324 @HttpMethod public final int httpMethod; 325 326 /** 327 * The HTTP request body, null otherwise. If the body is non-null, then {@code httpBody.length} 328 * will be non-zero. 329 */ 330 @Nullable public final byte[] httpBody; 331 332 /** 333 * Additional HTTP headers to use when requesting the data. 334 * 335 * <p>Note: This map is for additional headers specific to the data being requested. It does not 336 * include headers that are set directly by {@link HttpDataSource} implementations. In particular, 337 * this means the following headers are not included: 338 * 339 * <ul> 340 * <li>{@code Range}: {@link HttpDataSource} implementations derive the {@code Range} header 341 * from {@link #position} and {@link #length}. 342 * <li>{@code Accept-Encoding}: {@link HttpDataSource} implementations derive the {@code 343 * Accept-Encoding} header based on whether {@link #flags} includes {@link 344 * #FLAG_ALLOW_GZIP}. 345 * <li>{@code User-Agent}: {@link HttpDataSource} implementations set the {@code User-Agent} 346 * header directly. 347 * <li>Other headers set at the {@link HttpDataSource} layer. I.e., headers set using {@link 348 * HttpDataSource#setRequestProperty(String, String)}, and using {@link 349 * HttpDataSource.RequestProperties#set(String, String)} on the default properties obtained 350 * from {@link HttpDataSource.Factory#getDefaultRequestProperties()}. 351 * </ul> 352 */ 353 public final Map<String, String> httpRequestHeaders; 354 355 /** 356 * The absolute position of the data in the full stream. 357 * 358 * @deprecated Use {@link #position} except for specific use cases where the absolute position 359 * within the original resource is required within a {@link DataSource} chain. Where the 360 * absolute position is required, use {@code uriPositionOffset + position}. 361 */ 362 @Deprecated public final long absoluteStreamPosition; 363 364 /** The position of the data when read from {@link #uri}. */ 365 public final long position; 366 367 /** 368 * The length of the data, or {@link C#LENGTH_UNSET}. 369 */ 370 public final long length; 371 372 /** 373 * A key that uniquely identifies the original stream. Used for cache indexing. May be null if the 374 * data spec is not intended to be used in conjunction with a cache. 375 */ 376 @Nullable public final String key; 377 378 /** Request {@link Flags flags}. */ 379 @Flags public final int flags; 380 381 /** 382 * Application specific data. 383 * 384 * <p>This field is intended for advanced use cases in which applications require the ability to 385 * attach custom data to {@link DataSpec} instances. The custom data should be immutable. 386 */ 387 @Nullable public final Object customData; 388 389 /** 390 * Constructs an instance. 391 * 392 * @param uri {@link #uri}. 393 */ DataSpec(Uri uri)394 public DataSpec(Uri uri) { 395 this(uri, /* position= */ 0, /* length= */ C.LENGTH_UNSET); 396 } 397 398 /** 399 * Constructs an instance. 400 * 401 * @param uri {@link #uri}. 402 * @param position {@link #position}. 403 * @param length {@link #length}. 404 */ DataSpec(Uri uri, long position, long length)405 public DataSpec(Uri uri, long position, long length) { 406 this( 407 uri, 408 /* uriPositionOffset= */ 0, 409 HTTP_METHOD_GET, 410 /* httpBody= */ null, 411 /* httpRequestHeaders= */ Collections.emptyMap(), 412 position, 413 length, 414 /* key= */ null, 415 /* flags= */ 0, 416 /* customData= */ null); 417 } 418 419 /** 420 * Constructs an instance. 421 * 422 * @deprecated Use {@link Builder}. 423 * @param uri {@link #uri}. 424 * @param flags {@link #flags}. 425 */ 426 @SuppressWarnings("deprecation") 427 @Deprecated DataSpec(Uri uri, @Flags int flags)428 public DataSpec(Uri uri, @Flags int flags) { 429 this(uri, /* position= */ 0, C.LENGTH_UNSET, /* key= */ null, flags); 430 } 431 432 /** 433 * Constructs an instance. 434 * 435 * @deprecated Use {@link Builder}. 436 * @param uri {@link #uri}. 437 * @param position {@link #position}. 438 * @param length {@link #length}. 439 * @param key {@link #key}. 440 */ 441 @SuppressWarnings("deprecation") 442 @Deprecated DataSpec(Uri uri, long position, long length, @Nullable String key)443 public DataSpec(Uri uri, long position, long length, @Nullable String key) { 444 this(uri, position, position, length, key, /* flags= */ 0); 445 } 446 447 /** 448 * Constructs an instance. 449 * 450 * @deprecated Use {@link Builder}. 451 * @param uri {@link #uri}. 452 * @param position {@link #position}. 453 * @param length {@link #length}. 454 * @param key {@link #key}. 455 * @param flags {@link #flags}. 456 */ 457 @SuppressWarnings("deprecation") 458 @Deprecated DataSpec(Uri uri, long position, long length, @Nullable String key, @Flags int flags)459 public DataSpec(Uri uri, long position, long length, @Nullable String key, @Flags int flags) { 460 this(uri, position, position, length, key, flags); 461 } 462 463 /** 464 * Constructs an instance. 465 * 466 * @deprecated Use {@link Builder}. 467 * @param uri {@link #uri}. 468 * @param position {@link #position}, equal to {@link #position}. 469 * @param length {@link #length}. 470 * @param key {@link #key}. 471 * @param flags {@link #flags}. 472 * @param httpRequestHeaders {@link #httpRequestHeaders} 473 */ 474 @SuppressWarnings("deprecation") 475 @Deprecated DataSpec( Uri uri, long position, long length, @Nullable String key, @Flags int flags, Map<String, String> httpRequestHeaders)476 public DataSpec( 477 Uri uri, 478 long position, 479 long length, 480 @Nullable String key, 481 @Flags int flags, 482 Map<String, String> httpRequestHeaders) { 483 this( 484 uri, 485 HTTP_METHOD_GET, 486 /* httpBody= */ null, 487 position, 488 position, 489 length, 490 key, 491 flags, 492 httpRequestHeaders); 493 } 494 495 /** 496 * Constructs an instance where {@link #uriPositionOffset} may be non-zero. 497 * 498 * @deprecated Use {@link Builder}. 499 * @param uri {@link #uri}. 500 * @param absoluteStreamPosition The sum of {@link #uriPositionOffset} and {@link #position}. 501 * @param position {@link #position}. 502 * @param length {@link #length}. 503 * @param key {@link #key}. 504 * @param flags {@link #flags}. 505 */ 506 @SuppressWarnings("deprecation") 507 @Deprecated DataSpec( Uri uri, long absoluteStreamPosition, long position, long length, @Nullable String key, @Flags int flags)508 public DataSpec( 509 Uri uri, 510 long absoluteStreamPosition, 511 long position, 512 long length, 513 @Nullable String key, 514 @Flags int flags) { 515 this(uri, /* postBody= */ null, absoluteStreamPosition, position, length, key, flags); 516 } 517 518 /** 519 * Construct a instance where {@link #uriPositionOffset} may be non-zero. The {@link #httpMethod} 520 * is inferred from {@code postBody}. If {@code postBody} is non-null then {@link #httpMethod} is 521 * set to {@link #HTTP_METHOD_POST}. If {@code postBody} is null then {@link #httpMethod} is set 522 * to {@link #HTTP_METHOD_GET}. 523 * 524 * @deprecated Use {@link Builder}. 525 * @param uri {@link #uri}. 526 * @param postBody {@link #httpBody} The body of the HTTP request, which is also used to infer the 527 * {@link #httpMethod}. 528 * @param absoluteStreamPosition The sum of {@link #uriPositionOffset} and {@link #position}. 529 * @param position {@link #position}. 530 * @param length {@link #length}. 531 * @param key {@link #key}. 532 * @param flags {@link #flags}. 533 */ 534 @SuppressWarnings("deprecation") 535 @Deprecated DataSpec( Uri uri, @Nullable byte[] postBody, long absoluteStreamPosition, long position, long length, @Nullable String key, @Flags int flags)536 public DataSpec( 537 Uri uri, 538 @Nullable byte[] postBody, 539 long absoluteStreamPosition, 540 long position, 541 long length, 542 @Nullable String key, 543 @Flags int flags) { 544 this( 545 uri, 546 /* httpMethod= */ postBody != null ? HTTP_METHOD_POST : HTTP_METHOD_GET, 547 /* httpBody= */ postBody, 548 absoluteStreamPosition, 549 position, 550 length, 551 key, 552 flags); 553 } 554 555 /** 556 * Construct a instance where {@link #uriPositionOffset} may be non-zero. 557 * 558 * @deprecated Use {@link Builder}. 559 * @param uri {@link #uri}. 560 * @param httpMethod {@link #httpMethod}. 561 * @param httpBody {@link #httpBody}. 562 * @param absoluteStreamPosition The sum of {@link #uriPositionOffset} and {@link #position}. 563 * @param position {@link #position}. 564 * @param length {@link #length}. 565 * @param key {@link #key}. 566 * @param flags {@link #flags}. 567 */ 568 @SuppressWarnings("deprecation") 569 @Deprecated DataSpec( Uri uri, @HttpMethod int httpMethod, @Nullable byte[] httpBody, long absoluteStreamPosition, long position, long length, @Nullable String key, @Flags int flags)570 public DataSpec( 571 Uri uri, 572 @HttpMethod int httpMethod, 573 @Nullable byte[] httpBody, 574 long absoluteStreamPosition, 575 long position, 576 long length, 577 @Nullable String key, 578 @Flags int flags) { 579 this( 580 uri, 581 httpMethod, 582 httpBody, 583 absoluteStreamPosition, 584 position, 585 length, 586 key, 587 flags, 588 /* httpRequestHeaders= */ Collections.emptyMap()); 589 } 590 591 /** 592 * Construct a instance where {@link #uriPositionOffset} may be non-zero. 593 * 594 * @deprecated Use {@link Builder}. 595 * @param uri {@link #uri}. 596 * @param httpMethod {@link #httpMethod}. 597 * @param httpBody {@link #httpBody}. 598 * @param absoluteStreamPosition The sum of {@link #uriPositionOffset} and {@link #position}. 599 * @param position {@link #position}. 600 * @param length {@link #length}. 601 * @param key {@link #key}. 602 * @param flags {@link #flags}. 603 * @param httpRequestHeaders {@link #httpRequestHeaders}. 604 */ 605 @Deprecated DataSpec( Uri uri, @HttpMethod int httpMethod, @Nullable byte[] httpBody, long absoluteStreamPosition, long position, long length, @Nullable String key, @Flags int flags, Map<String, String> httpRequestHeaders)606 public DataSpec( 607 Uri uri, 608 @HttpMethod int httpMethod, 609 @Nullable byte[] httpBody, 610 long absoluteStreamPosition, 611 long position, 612 long length, 613 @Nullable String key, 614 @Flags int flags, 615 Map<String, String> httpRequestHeaders) { 616 this( 617 uri, 618 /* uriPositionOffset= */ absoluteStreamPosition - position, 619 httpMethod, 620 httpBody, 621 httpRequestHeaders, 622 position, 623 length, 624 key, 625 flags, 626 /* customData= */ null); 627 } 628 629 @SuppressWarnings("deprecation") DataSpec( Uri uri, long uriPositionOffset, @HttpMethod int httpMethod, @Nullable byte[] httpBody, Map<String, String> httpRequestHeaders, long position, long length, @Nullable String key, @Flags int flags, @Nullable Object customData)630 private DataSpec( 631 Uri uri, 632 long uriPositionOffset, 633 @HttpMethod int httpMethod, 634 @Nullable byte[] httpBody, 635 Map<String, String> httpRequestHeaders, 636 long position, 637 long length, 638 @Nullable String key, 639 @Flags int flags, 640 @Nullable Object customData) { 641 // TODO: Replace this assertion with a stricter one checking "uriPositionOffset >= 0", after 642 // validating there are no violations in ExoPlayer and 1P apps. 643 Assertions.checkArgument(uriPositionOffset + position >= 0); 644 Assertions.checkArgument(position >= 0); 645 Assertions.checkArgument(length > 0 || length == C.LENGTH_UNSET); 646 this.uri = uri; 647 this.uriPositionOffset = uriPositionOffset; 648 this.httpMethod = httpMethod; 649 this.httpBody = httpBody != null && httpBody.length != 0 ? httpBody : null; 650 this.httpRequestHeaders = Collections.unmodifiableMap(new HashMap<>(httpRequestHeaders)); 651 this.position = position; 652 this.absoluteStreamPosition = uriPositionOffset + position; 653 this.length = length; 654 this.key = key; 655 this.flags = flags; 656 this.customData = customData; 657 } 658 659 /** 660 * Returns whether the given flag is set. 661 * 662 * @param flag Flag to be checked if it is set. 663 */ isFlagSet(@lags int flag)664 public boolean isFlagSet(@Flags int flag) { 665 return (this.flags & flag) == flag; 666 } 667 668 /** 669 * Returns the uppercase HTTP method name (e.g., "GET", "POST", "HEAD") corresponding to the 670 * {@link #httpMethod}. 671 */ getHttpMethodString()672 public final String getHttpMethodString() { 673 return getStringForHttpMethod(httpMethod); 674 } 675 676 /** Returns a {@link DataSpec.Builder} initialized with the values of this instance. */ buildUpon()677 public DataSpec.Builder buildUpon() { 678 return new Builder(this); 679 } 680 681 /** 682 * Returns a data spec that represents a subrange of the data defined by this DataSpec. The 683 * subrange includes data from the offset up to the end of this DataSpec. 684 * 685 * @param offset The offset of the subrange. 686 * @return A data spec that represents a subrange of the data defined by this DataSpec. 687 */ subrange(long offset)688 public DataSpec subrange(long offset) { 689 return subrange(offset, length == C.LENGTH_UNSET ? C.LENGTH_UNSET : length - offset); 690 } 691 692 /** 693 * Returns a data spec that represents a subrange of the data defined by this DataSpec. 694 * 695 * @param offset The offset of the subrange. 696 * @param length The length of the subrange. 697 * @return A data spec that represents a subrange of the data defined by this DataSpec. 698 */ subrange(long offset, long length)699 public DataSpec subrange(long offset, long length) { 700 if (offset == 0 && this.length == length) { 701 return this; 702 } else { 703 return new DataSpec( 704 uri, 705 uriPositionOffset, 706 httpMethod, 707 httpBody, 708 httpRequestHeaders, 709 position + offset, 710 length, 711 key, 712 flags, 713 customData); 714 } 715 } 716 717 /** 718 * Returns a copy of this data spec with the specified Uri. 719 * 720 * @param uri The new source {@link Uri}. 721 * @return The copied data spec with the specified Uri. 722 */ withUri(Uri uri)723 public DataSpec withUri(Uri uri) { 724 return new DataSpec( 725 uri, 726 uriPositionOffset, 727 httpMethod, 728 httpBody, 729 httpRequestHeaders, 730 position, 731 length, 732 key, 733 flags, 734 customData); 735 } 736 737 /** 738 * Returns a copy of this data spec with the specified HTTP request headers. Headers already in 739 * the data spec are not copied to the new instance. 740 * 741 * @param httpRequestHeaders The HTTP request headers. 742 * @return The copied data spec with the specified HTTP request headers. 743 */ withRequestHeaders(Map<String, String> httpRequestHeaders)744 public DataSpec withRequestHeaders(Map<String, String> httpRequestHeaders) { 745 return new DataSpec( 746 uri, 747 uriPositionOffset, 748 httpMethod, 749 httpBody, 750 httpRequestHeaders, 751 position, 752 length, 753 key, 754 flags, 755 customData); 756 } 757 758 /** 759 * Returns a copy this data spec with additional HTTP request headers. Headers in {@code 760 * additionalHttpRequestHeaders} will overwrite any headers already in the data spec that have the 761 * same keys. 762 * 763 * @param additionalHttpRequestHeaders The additional HTTP request headers. 764 * @return The copied data spec with the additional HTTP request headers. 765 */ withAdditionalHeaders(Map<String, String> additionalHttpRequestHeaders)766 public DataSpec withAdditionalHeaders(Map<String, String> additionalHttpRequestHeaders) { 767 Map<String, String> httpRequestHeaders = new HashMap<>(this.httpRequestHeaders); 768 httpRequestHeaders.putAll(additionalHttpRequestHeaders); 769 return new DataSpec( 770 uri, 771 uriPositionOffset, 772 httpMethod, 773 httpBody, 774 httpRequestHeaders, 775 position, 776 length, 777 key, 778 flags, 779 customData); 780 } 781 782 @Override toString()783 public String toString() { 784 return "DataSpec[" 785 + getHttpMethodString() 786 + " " 787 + uri 788 + ", " 789 + position 790 + ", " 791 + length 792 + ", " 793 + key 794 + ", " 795 + flags 796 + "]"; 797 } 798 } 799