intercept method

  1. @override
Future<HttpResponse> intercept(
  1. HttpRequest request,
  2. CancellationToken parent,
  3. HttpRequestHandler next
)
override

Implementation

@override
Future<HttpResponse> intercept(HttpRequest request, CancellationToken parent,
    HttpRequestHandler next) async {
  if (!{HttpMethod.get, HttpMethod.head}.contains(request.method) ||
      request.body != null ||
      maxAttempts == 1) {
    return next(request, parent);
  }
  final result = Completer<HttpResponse>();
  final tokens =
      List.generate(maxAttempts, (_) => CancellationToken.linked([parent]));
  var failures = 0;
  for (var attempt = 0; attempt < maxAttempts; attempt++) {
    final token = tokens[attempt];
    unawaited(Future<void>(() async {
      try {
        if (attempt > 0) await token.wait(delay * attempt);
        token.throwIfCanceled();
        final response = await next(request.copyWith(), token);
        if (parent.isCanceled) {
          await response.dispose();
          parent.throwIfCanceled();
        }
        if (result.isCompleted) {
          await response.dispose();
          token.dispose();
          return;
        }
        for (final other in tokens) {
          if (!identical(other, token)) other.cancel('Hedge lost.');
        }
        result.complete(
            response.withBody(response.body, onClose: token.dispose));
      } catch (error, stack) {
        failures++;
        token.dispose();
        if (!result.isCompleted && failures == maxAttempts) {
          result.completeError(error, stack);
        }
      }
    }));
  }
  return parent.race(result.future);
}