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<StreamedResponse> send(BaseRequest request) async {
  final timing = HttpClientConnectTiming();
  final ttfbSw = Stopwatch()..start();

  return runZoned(() async {
    final recorder = HttpSpanRecorder.start(
      tracerName: InstrumentationScopes.http,
      method: request.method,
      url: request.url,
      supportedPhases: _phases,
    );

    W3CTraceContextPropagator().inject(
      contextWithSpan(Context.current, recorder.span),
      request.headers,
      _TextMapSetter(),
    );
    recorder.applyRequestHeaders(request.headers);

    try {
      final response = await _httpClient.send(request);
      recorder.recordPhase(HttpTimingPhase.ttfb, elapsedMs(ttfbSw));
      recorder.applyConnectTiming(timing);
      recorder.applyResponse(
        statusCode: response.statusCode,
        reasonPhrase: response.reasonPhrase,
        protocolVersion: _protocolVersion(response),
      );
      recorder.applyResponseHeaders(response.headers);

      if (timing.peerAddress == null) {
        await recorder.resolvePeerWithDns();
      } else {
        recorder.applyPeer(address: timing.peerAddress);
      }

      return _TimedStreamedResponse(response, recorder);
    } catch (e, st) {
      recorder.applyConnectTiming(timing);
      if (timing.peerAddress == null) {
        await recorder.resolvePeerWithDns();
      }
      recorder.onError(e, st);
      recorder.end();
      rethrow;
    }
  }, zoneValues: {HttpClientConnectTiming.zoneKey: timing});
}