send method

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

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;
  }
}