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 ClientExceptions.
Implementation
@override
Future<StreamedResponse> send(BaseRequest request) async {
if (_closed) {
throw ClientException(
'HTTP request failed. Client is already closed.',
request.url,
);
}
if (request.url.scheme != 'https') {
throw ClientException(
'Http2Client only supports https (got "${request.url.scheme}").',
request.url,
);
}
List<int>? bodyBytes;
Future<StreamedResponse> attempt() async {
final lease = await _poolFor(request.url).acquire();
try {
bodyBytes ??= await request.finalize().toBytes();
} catch (_) {
lease.release();
rethrow;
}
try {
return await _sendOverHttp2(lease, request, bodyBytes!);
} catch (_) {
lease.markFailed();
lease.release();
rethrow;
}
}
return attempt()
.catchError(
(Object _) => attempt(),
test: (error) => error is _ConnectionClosedByPeer,
)
.catchError(
(Object error, StackTrace stackTrace) => Error.throwWithStackTrace(
ClientException('$error', request.url),
stackTrace,
),
test: (error) => error is! ClientException,
);
}