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<StreamedResponse> send(BaseRequest request) async {
final splitter = StreamSplitter(request.finalize());
var aborted = false;
if (request case Abortable(:final abortTrigger?)) {
unawaited(abortTrigger.whenComplete(() => aborted = true));
}
var i = 0;
for (;;) {
StreamedResponse? response;
try {
// If the inner client doesn't support abortable, we still try to avoid
// re-requests when aborted
if (aborted) throw RequestAbortedException(request.url);
response = await _inner.send(_copyRequest(request, splitter.split()));
} on RequestAbortedException {
rethrow;
} catch (error, stackTrace) {
if (i == _retries || !await _whenError(error, stackTrace)) rethrow;
}
if (response != null) {
if (i == _retries || !await _when(response)) return response;
// Make sure the response stream is listened to so that we don't leave
// dangling connections.
unawaited(response.stream.listen((_) {}).cancel().catchError((_) {}));
}
await Future<void>.delayed(_delay(i));
await _onRetry?.call(request, response, i);
i++;
}
}