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',
);
}
}