send method

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

Sends an HTTP request and asynchronously returns the response.

Implementation

@override
Future<StreamedResponse> send(BaseRequest request) async {
  if (_isClosed) {
    throw ClientException(
        'HTTP request failed. Client is already closed.', request.url);
  }
  var bytes = await request.finalize().toBytes();
  var xhr = XMLHttpRequest();
  _xhrs.add(xhr);
  xhr
    ..open(request.method, '${request.url}', true)
    ..responseType = 'arraybuffer'
    ..withCredentials = withCredentials;
  for (var header in request.headers.entries) {
    xhr.setRequestHeader(header.key, header.value);
  }

  var completer = Completer<StreamedResponse>();

  unawaited(xhr.onLoad.first.then((_) {
    if (xhr.responseHeaders['content-length'] case final contentLengthHeader
        when contentLengthHeader != null &&
            !_digitRegex.hasMatch(contentLengthHeader)) {
      completer.completeError(ClientException(
        'Invalid content-length header [$contentLengthHeader].',
        request.url,
      ));
      return;
    }
    var body = (xhr.response as JSArrayBuffer).toDart.asUint8List();
    var responseUrl = xhr.responseURL;
    var url = responseUrl.isNotEmpty ? Uri.parse(responseUrl) : request.url;
    completer.complete(StreamedResponseV2(
        ByteStream.fromBytes(body), xhr.status,
        contentLength: body.length,
        request: request,
        url: url,
        headers: xhr.responseHeaders,
        reasonPhrase: xhr.statusText));
  }));

  unawaited(xhr.onError.first.then((_) {
    // Unfortunately, the underlying XMLHttpRequest API doesn't expose any
    // specific information about the error itself.
    completer.completeError(
        ClientException('XMLHttpRequest error.', request.url),
        StackTrace.current);
  }));

  xhr.send(bytes.toJS);

  try {
    return await completer.future;
  } finally {
    _xhrs.remove(xhr);
  }
}