handleRequest method
Handles an incoming HTTP request.
Implementation
Future<bool> handleRequest(RequestContext req, ResponseContext res) async {
if (req is HttpRequestContext && res is HttpResponseContext) {
if (!WebSocketTransformer.isUpgradeRequest(req.rawRequest!)) {
throw AngelHttpException.badRequest();
}
res.detach();
var ws = await WebSocketTransformer.upgrade(req.rawRequest!);
var channel = IOWebSocketChannel(ws);
var socket = WebSocketContext(channel, req, res);
scheduleMicrotask(() => handleClient(socket));
return false;
} else if (req is Http2RequestContext && res is Http2ResponseContext) {
var connection =
req.headers?['connection']?.map((s) => s.toLowerCase().trim());
var upgrade = req.headers?.value('upgrade')?.toLowerCase();
var version = req.headers?.value('sec-websocket-version');
var key = req.headers?.value('sec-websocket-key');
var protocol = req.headers?.value('sec-websocket-protocol');
if (connection == null) {
throw AngelHttpException.badRequest(
message: 'Missing `connection` header.');
} else if (!connection.contains('upgrade')) {
throw AngelHttpException.badRequest(
message: 'Missing "upgrade" in `connection` header.');
} else if (upgrade != 'websocket') {
throw AngelHttpException.badRequest(
message: 'The `upgrade` header must equal "websocket".');
} else if (version != '13') {
throw AngelHttpException.badRequest(
message: 'The `sec-websocket-version` header must equal "13".');
} else if (key == null) {
throw AngelHttpException.badRequest(
message: 'Missing `sec-websocket-key` header.');
} else if (protocol != null &&
allowedProtocols.isNotEmpty &&
!allowedProtocols.contains(protocol)) {
throw AngelHttpException.badRequest(
message: 'Disallowed `sec-websocket-protocol` header "$protocol".');
} else {
var stream = res.detach();
var ctrl = StreamChannelController<List<int>>();
ctrl.local.stream.listen((buf) {
stream.sendData(buf);
}, onDone: () {
stream.outgoingMessages.close();
});
if (req.hasParsedBody) {
await ctrl.local.sink.close();
} else {
await req.body.pipe(ctrl.local.sink);
}
var sink = utf8.encoder.startChunkedConversion(ctrl.foreign.sink);
sink.add('HTTP/1.1 101 Switching Protocols\r\n'
'Upgrade: websocket\r\n'
'Connection: Upgrade\r\n'
'Sec-WebSocket-Accept: ${WebSocketChannel.signKey(key)}\r\n');
if (protocol != null) sink.add('Sec-WebSocket-Protocol: $protocol\r\n');
sink.add('\r\n');
//var ws = IOWebSocketChannel.connect(ctrl.foreign);
var socket = WebSocketContext(ctrl.foreign, req, res);
scheduleMicrotask(() => handleClient(socket));
return false;
}
} else {
throw ArgumentError(
'Not an HTTP/1.1 or HTTP/2 RequestContext+ResponseContext pair: $req, $res');
}
}