send method

  1. @override
Future<StreamedResponse> send(
  1. BaseRequest request, {
  2. CancellationToken? cancellationToken,
})
override

Sends an HTTP request and asynchronously returns the response.

Implementation

@override
Future<StreamedResponse> send(
  BaseRequest request, {
  CancellationToken? cancellationToken,
}) async {
  if (cancellationToken?.isCancelled ?? false) {
    throw cancellationToken!.exception!;
  } else if (_isClosed) {
    throw ClientException(
        'HTTP request failed. Client is already closed.', request.url);
  }

  HttpRequest? xhr = HttpRequest();
  final completer = CancellableCompleter<StreamedResponse>.sync(
    cancellationToken,
    onCancel: () {
      _xhrs.remove(xhr);
      xhr.abort();
    },
  );

  unawaited(request.finalize().toBytes().then((bytes) async {
    // Don't continue if the request has been cancelled at this point
    if (cancellationToken?.isCancelled ?? false) return;

    // Prepare the request
    _xhrs.add(xhr);
    xhr
      ..open(request.method, '${request.url}', async: true)
      ..responseType = 'arraybuffer'
      ..withCredentials = withCredentials;
    request.headers.forEach(xhr.setRequestHeader);

    // Prepare the response handler
    unawaited(xhr.onLoad.first.then((_) {
      var body = (xhr.response as ByteBuffer).asUint8List();
      completer.complete(StreamedResponse(
        ByteStream.fromBytes(body),
        xhr.status!,
        contentLength: body.length,
        request: request,
        headers: xhr.responseHeaders,
        reasonPhrase: xhr.statusText,
      ));
      _xhrs.remove(xhr);
    }));

    // Prepare the error handler
    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,
      );
      _xhrs.remove(xhr);
    }));

    // Send the request
    xhr.send(bytes);
  }));

  return completer.future;
}