send method

  1. @override
Future<StreamedResponse> send(
  1. BaseRequest originalRequest
)

Sends an HTTP request and asynchronously returns the response.

Implementation

@override
Future<StreamedResponse> send(BaseRequest originalRequest) async {
  final request = $HandleFeatures.disableAsyncDeserializationWithHandle
      ? markHandleUsageInRequestHeaders(originalRequest)
      : originalRequest;
  int retryCount = 0;
  BaseRequest latestRequest = request;
  StreamedResponse? response;

  StreamController<List<int>>? sendBodyStreamController;
  StreamController<List<int>>? retryBodyStreamController;
  StreamSubscription<List<int>>? bodyStreamSubscription;

  FutureOr<void> disposeLatest() {
    bodyStreamSubscription?.cancel();
    sendBodyStreamController?.close();
    retryBodyStreamController?.close();
    bodyStreamSubscription = null;
    sendBodyStreamController = null;
    retryBodyStreamController = null;
  }

  do {
    try {
      disposeLatest();
      final FinalizedBodyStream body = latestRequest.finalizedBodyStream;

      sendBodyStreamController = StreamController<List<int>>();
      retryBodyStreamController = StreamController<List<int>>();
      bodyStreamSubscription = body.addStreamToSinks([
        sendBodyStreamController!.sink,
        retryBodyStreamController!.sink,
      ]);
      try {
        response = await inner.send(
          latestRequest.createCopy(sendBodyStreamController!.stream),
        );
        if (!await retryRequestWhen(response, retryCount)) {
          return response;
        }
        unawaitedResponse(response);
      } catch (e, s) {
        if (!await retryRequestWhenError(e, s, retryCount)) rethrow;
      }

      final delay = calculateDelay(retryCount);
      if (delay != null) {
        await Future.delayed(delay);
      }

      bool didConsumeBodyInCopiedRequest = false;

      FinalizedBodyStream getBodyStream() {
        didConsumeBodyInCopiedRequest = true;
        return retryBodyStreamController!.stream;
      }

      latestRequest = await getUpdatedRequest(
        request,
        latestRequest,
        getBodyStream,
        response,
        retryCount,
      );

      if (didConsumeBodyInCopiedRequest) {
        retryBodyStreamController!.close();
      }

      await onRequestRetry(latestRequest, response, retryCount);
    } on ClientException {
      disposeLatest();
      rethrow;
    } catch (e, s) {
      disposeLatest();
      throw HandleException(
        'Unexpected exception while retrying a request',
        uri: request.url,
        statusCode: response?.statusCode,
        innerException: e,
        innerStackTrace: s,
      );
    }

    retryCount++;
  } while (retryCount < HANDLE_RETRY_MAX_LIMIT);

  disposeLatest();
  throw HandleRetryLimitExceededException(
    'Too many retries',
    retryCount,
    uri: request.url,
    statusCode: response?.statusCode,
  );
}