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 {
  if (_ignorePattern != null && request.url.path.startsWith(_ignorePattern!)) {
    return await _inner.send(request);
  }

  // Only handle http Requests
  // https://github.com/GetDutchie/brick/issues/440#issuecomment-2357547961
  if (request is! http.Request) {
    return await _inner.send(request);
  }

  final cachePolicy = request.headers.remove(policyHeader);
  final skipCache = cachePolicy == 'requireRemote';
  final cacheItem = RestRequestSqliteCache(request);
  _logger.finest('sending: ${cacheItem.toSqlite()}');

  // Process the request immediately and forward any warnings to the caller
  if (skipCache) return await _inner.send(request);

  // "Pull" requests are ignored. See documentation of `RequestSqliteCache#requestIsPush`.
  if (cacheItem.requestIsPush) {
    final db = await requestManager.getDb();
    // Log immediately before we make the request
    await cacheItem.insertOrUpdate(db, logger: _logger);
  }

  /// When the request is null or an error has occurred, an error-like
  /// response is required because null is unacceptable in [BaseClient]
  final genericErrorResponse = http.StreamedResponse(
    Stream.fromFuture(Future.value('unknown internal error'.codeUnits)),
    501,
    request: request,
  );

  try {
    // Attempt to make HTTP Request
    final resp = await _inner.send(request);

    if (cacheItem.requestIsPush) {
      if (!reattemptForStatusCodes.contains(resp.statusCode)) {
        final db = await requestManager.getDb();
        // request was successfully sent and can be removed
        _logger.finest('removing from queue: ${cacheItem.toSqlite()}');
        await cacheItem.delete(db);
      } else if (onReattempt != null) {
        _logger.finest(
          'request failed, will be reattempted: ${cacheItem.toSqlite()}',
        );
        onReattempt?.call(request, resp.statusCode);
      }
    }

    return resp;
  } catch (e) {
    // e.g. SocketExceptions will be caught here
    onRequestException?.call(request, e);
    _logger.warning('#send: $e');
  } finally {
    // unlock the request for a later a reattempt
    final db = await requestManager.getDb();
    await cacheItem.unlock(db);
  }

  return genericErrorResponse;
}