use of androidx.media3.datasource.DataSpec in project media by androidx.
the class DefaultHttpDataSource method makeConnection.
/**
* Establishes a connection, following redirects to do so where permitted.
*/
private HttpURLConnection makeConnection(DataSpec dataSpec) throws IOException {
URL url = new URL(dataSpec.uri.toString());
@HttpMethod int httpMethod = dataSpec.httpMethod;
@Nullable byte[] httpBody = dataSpec.httpBody;
long position = dataSpec.position;
long length = dataSpec.length;
boolean allowGzip = dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_GZIP);
if (!allowCrossProtocolRedirects && !keepPostFor302Redirects) {
// automatically. This is the behavior we want, so use it.
return makeConnection(url, httpMethod, httpBody, position, length, allowGzip, /* followRedirects= */
true, dataSpec.httpRequestHeaders);
}
// We need to handle redirects ourselves to allow cross-protocol redirects or to keep the POST
// request method for 302.
int redirectCount = 0;
while (redirectCount++ <= MAX_REDIRECTS) {
HttpURLConnection connection = makeConnection(url, httpMethod, httpBody, position, length, allowGzip, /* followRedirects= */
false, dataSpec.httpRequestHeaders);
int responseCode = connection.getResponseCode();
String location = connection.getHeaderField("Location");
if ((httpMethod == DataSpec.HTTP_METHOD_GET || httpMethod == DataSpec.HTTP_METHOD_HEAD) && (responseCode == HttpURLConnection.HTTP_MULT_CHOICE || responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_SEE_OTHER || responseCode == HTTP_STATUS_TEMPORARY_REDIRECT || responseCode == HTTP_STATUS_PERMANENT_REDIRECT)) {
connection.disconnect();
url = handleRedirect(url, location, dataSpec);
} else if (httpMethod == DataSpec.HTTP_METHOD_POST && (responseCode == HttpURLConnection.HTTP_MULT_CHOICE || responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_SEE_OTHER)) {
connection.disconnect();
boolean shouldKeepPost = keepPostFor302Redirects && responseCode == HttpURLConnection.HTTP_MOVED_TEMP;
if (!shouldKeepPost) {
// POST request follows the redirect and is transformed into a GET request.
httpMethod = DataSpec.HTTP_METHOD_GET;
httpBody = null;
}
url = handleRedirect(url, location, dataSpec);
} else {
return connection;
}
}
// If we get here we've been redirected more times than are permitted.
throw new HttpDataSourceException(new NoRouteToHostException("Too many redirects: " + redirectCount), dataSpec, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, HttpDataSourceException.TYPE_OPEN);
}
use of androidx.media3.datasource.DataSpec in project media by androidx.
the class CronetDataSourceTest method allowDirectExecutor.
@Test
public void allowDirectExecutor() throws HttpDataSourceException {
testDataSpec = new DataSpec(Uri.parse(TEST_URL));
mockResponseStartSuccess();
dataSourceUnderTest.open(testDataSpec);
verify(mockUrlRequestBuilder).allowDirectExecutor();
}
use of androidx.media3.datasource.DataSpec in project media by androidx.
the class CronetDataSourceTest method requestOpenGzippedCompressedReturnsDataSpecLength.
@Test
public void requestOpenGzippedCompressedReturnsDataSpecLength() throws HttpDataSourceException {
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 5000);
testResponseHeader.put("Content-Encoding", "gzip");
testResponseHeader.put("Content-Length", Long.toString(50L));
mockResponseStartSuccess();
assertThat(dataSourceUnderTest.open(testDataSpec)).isEqualTo(5000);
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec, /* isNetwork= */
true);
}
use of androidx.media3.datasource.DataSpec in project media by androidx.
the class CronetDataSourceTest method rangeRequestWith200Response.
@Test
public void rangeRequestWith200Response() throws HttpDataSourceException {
mockResponseStartSuccess();
mockReadSuccess(0, 7000);
// Server does not support range requests.
testUrlResponseInfo = createUrlResponseInfo(200);
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000);
long length = dataSourceUnderTest.open(testDataSpec);
assertThat(length).isEqualTo(5000);
byte[] returnedBuffer = new byte[16];
int bytesRead = dataSourceUnderTest.read(returnedBuffer, 0, 16);
assertThat(bytesRead).isEqualTo(16);
assertThat(returnedBuffer).isEqualTo(buildTestDataArray(1000, 16));
verify(mockTransferListener).onBytesTransferred(dataSourceUnderTest, testDataSpec, /* isNetwork= */
true, 16);
}
use of androidx.media3.datasource.DataSpec in project media by androidx.
the class OkHttpDataSource method open.
@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
this.dataSpec = dataSpec;
bytesRead = 0;
bytesToRead = 0;
transferInitializing(dataSpec);
Request request = makeRequest(dataSpec);
Response response;
ResponseBody responseBody;
try {
this.response = callFactory.newCall(request).execute();
response = this.response;
responseBody = Assertions.checkNotNull(response.body());
responseByteStream = responseBody.byteStream();
} catch (IOException e) {
throw HttpDataSourceException.createForIOException(e, dataSpec, HttpDataSourceException.TYPE_OPEN);
}
int responseCode = response.code();
// Check for a valid response code.
if (!response.isSuccessful()) {
if (responseCode == 416) {
long documentSize = HttpUtil.getDocumentSize(response.headers().get(HttpHeaders.CONTENT_RANGE));
if (dataSpec.position == documentSize) {
opened = true;
transferStarted(dataSpec);
return dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : 0;
}
}
byte[] errorResponseBody;
try {
errorResponseBody = Util.toByteArray(Assertions.checkNotNull(responseByteStream));
} catch (IOException e) {
errorResponseBody = Util.EMPTY_BYTE_ARRAY;
}
Map<String, List<String>> headers = response.headers().toMultimap();
closeConnectionQuietly();
@Nullable IOException cause = responseCode == 416 ? new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE) : null;
throw new InvalidResponseCodeException(responseCode, response.message(), cause, headers, dataSpec, errorResponseBody);
}
// Check for a valid content type.
@Nullable MediaType mediaType = responseBody.contentType();
String contentType = mediaType != null ? mediaType.toString() : "";
if (contentTypePredicate != null && !contentTypePredicate.apply(contentType)) {
closeConnectionQuietly();
throw new InvalidContentTypeException(contentType, dataSpec);
}
// If we requested a range starting from a non-zero position and received a 200 rather than a
// 206, then the server does not support partial requests. We'll need to manually skip to the
// requested position.
long bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0;
// Determine the length of the data to be read, after skipping.
if (dataSpec.length != C.LENGTH_UNSET) {
bytesToRead = dataSpec.length;
} else {
long contentLength = responseBody.contentLength();
bytesToRead = contentLength != -1 ? (contentLength - bytesToSkip) : C.LENGTH_UNSET;
}
opened = true;
transferStarted(dataSpec);
try {
skipFully(bytesToSkip, dataSpec);
} catch (HttpDataSourceException e) {
closeConnectionQuietly();
throw e;
}
return bytesToRead;
}
Aggregations