send method
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 ClientException
s.
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;
}