send method
Sends an HTTP request and asynchronously returns the response.
Implementers should call BaseRequest.finalize to get the body of the
request as a ByteStream. They shouldn't make any assumptions about the
state of the stream; it could have data written to it asynchronously at a
later point, or it could already be closed when it's returned. Any
internal HTTP errors should be wrapped as ClientExceptions.
Implementation
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
final decisionEngine = policy.decisionEngine ??
HttpRetryDecisionEngine.create(
config: httpConfig,
extractor: const CompositeHttpResponseExtractor([
PackageHttpResponseExtractor(),
DuckTypedHttpResponseExtractor(),
]),
);
final effectivePolicy = policy.copyWith(decisionEngine: decisionEngine);
final executor = RetryExecutor<http.StreamedResponse>(
() async {
final clonedRequest = _cloneRequest(request);
final response = await _innerClient.send(clonedRequest);
// Check if status code warrants a retry evaluation
if (httpConfig.retryableStatusCodes.contains(response.statusCode)) {
// Check method restriction before deciding to throw and retry
final method = request.method.toUpperCase();
if (httpConfig.retryableMethods == null ||
httpConfig.retryableMethods!.contains(method)) {
final bytes = await response.stream.toBytes();
final bufferedResponse = http.StreamedResponse(
http.ByteStream.fromBytes(bytes),
response.statusCode,
contentLength: response.contentLength ?? bytes.length,
request: response.request,
headers: response.headers,
isRedirect: response.isRedirect,
persistentConnection: response.persistentConnection,
reasonPhrase: response.reasonPhrase,
);
throw HttpRetryResponseException(
statusCode: response.statusCode,
headers: response.headers,
method: method,
finalResponse: bufferedResponse,
);
}
}
return response;
},
policy: effectivePolicy,
token: token,
logger: logger,
);
final result = await executor.execute();
if (result is RetrySuccess<http.StreamedResponse>) {
return result.unwrap();
} else {
final failure = result as RetryFailure<http.StreamedResponse>;
// If retries exhausted on a response exception, return the final streamed response cleanly
if (failure.error is HttpRetryResponseException) {
return (failure.error as HttpRetryResponseException).finalResponse;
}
// Otherwise rethrow original client error or socket exception
throw failure.error;
}
}