send method
Sends request and returns its response.
Implementations must stop request and response work when ServerRequest.cancelled completes.
Implementation
@override
Future<ServerResponse> send(ServerRequest request) async {
var callerCancelled = false;
final abortTrigger = request.cancelled?.then<void>(
(_) => callerCancelled = true,
onError: (Object _, StackTrace _) => callerCancelled = true,
);
final outgoing = http.AbortableRequest(
request.method.wire,
request.uri,
abortTrigger: abortTrigger,
);
for (final entry in request.headers.entries) {
if (_framingHeaders.contains(entry.key)) continue;
outgoing.headers[entry.key] = entry.value.join(', ');
}
outgoing.bodyBytes = await runUntilRpcCancelled(
() => _readBytes(
stopOnRpcCancellation(request.body, request.cancelled),
maxRequestBodyBytes,
),
request.cancelled,
);
Future<http.StreamedResponse>? pending;
late final http.StreamedResponse incoming;
try {
incoming = await runUntilRpcCancelled(
() => pending = _client.send(outgoing),
request.cancelled,
);
} on http.RequestAbortedException catch (_, stackTrace) {
if (callerCancelled) {
Error.throwWithStackTrace(const RpcCancelledException(), stackTrace);
}
rethrow;
} on RpcCancelledException {
final lateResponse = pending;
if (lateResponse != null) {
unawaited(
lateResponse.then<void>(
(response) => _cancelBody(response.stream),
onError: (Object _, StackTrace _) {},
),
);
}
rethrow;
}
return ServerResponse(
status: incoming.statusCode,
reason: incoming.reasonPhrase,
headers: Headers.single(incoming.headers),
body: incoming.stream.handleError((Object error, StackTrace stackTrace) {
if (callerCancelled) {
Error.throwWithStackTrace(const RpcCancelledException(), stackTrace);
}
Error.throwWithStackTrace(error, stackTrace);
}, test: (error) => error is http.RequestAbortedException),
);
}