send method

  1. @override
Future<HttpResponse> send(
  1. HttpRequest request,
  2. CancellationToken cancellationToken
)
override

Implementation

@override
Future<HttpResponse> send(
    HttpRequest request, CancellationToken cancellationToken) async {
  var current = request;
  for (var redirect = 0;; redirect++) {
    final response = await _sendOnce(current, cancellationToken);
    if (!_options.followRedirects ||
        !{301, 302, 303, 307, 308}.contains(response.statusCode)) {
      return response;
    }
    final locations = response.headers['location'];
    if (locations.isEmpty) return response;
    if (redirect >= _options.maxRedirects) {
      await response.dispose();
      throw StateError('Maximum redirects exceeded.');
    }
    final toGet =
        response.statusCode == 303 && current.method != HttpMethod.head;
    if (!toGet && current.body?.isReplayable == false) return response;
    if ({301, 302}.contains(response.statusCode) &&
        !{HttpMethod.get, HttpMethod.head}.contains(current.method)) {
      return response;
    }
    Uri target;
    try {
      target = current.uri.resolve(locations.first);
    } catch (_) {
      await response.dispose();
      rethrow;
    }
    if (!{'http', 'https'}.contains(target.scheme) ||
        target.host.isEmpty ||
        target.userInfo.isNotEmpty ||
        (current.uri.scheme == 'https' && target.scheme == 'http')) {
      await response.dispose();
      throw StateError('Unsafe redirect destination.');
    }
    var headers = current.headers;
    if (target.origin != current.uri.origin) {
      headers =
          headers.without(['authorization', 'proxy-authorization', 'cookie']);
    }
    if (toGet) {
      headers = headers
          .without(['content-type', 'content-length', 'transfer-encoding']);
    }
    current = current.copyWith(
        uri: target,
        headers: headers,
        method: toGet ? HttpMethod.get : current.method,
        removeBody: toGet);
    await response.dispose();
  }
}