webSocketHandler function

Future<Response> Function(Request) webSocketHandler(
  1. ConnectionCallback onConnection, {
  2. Iterable<String>? protocols,
  3. Iterable<String>? allowedOrigins,
  4. Duration? pingInterval,
  5. int maxMessageSize = 1024 * 1024,
})

Shelf-style callback and options, with bounded native message queues. Use sink.addStream (or NativeWebSocketChannel.send) for backpressure. sink.add buffers in Dart and applies backpressure to the network, matching dart:io WebSocket semantics without throwing on a full queue. Messages default to at most 1 MiB.

Implementation

Future<Response> Function(Request) webSocketHandler(
  ConnectionCallback onConnection, {
  Iterable<String>? protocols,
  Iterable<String>? allowedOrigins,
  Duration? pingInterval,
  int maxMessageSize = 1024 * 1024,
}) {
  if (maxMessageSize <= 0 || maxMessageSize > 64 * 1024 * 1024) {
    throw ArgumentError.value(maxMessageSize, 'maxMessageSize');
  }
  if (pingInterval != null && pingInterval <= Duration.zero) {
    throw ArgumentError.value(pingInterval, 'pingInterval');
  }
  final origins = allowedOrigins?.map((o) => o.toLowerCase()).toSet();
  final supported = protocols?.toSet() ?? <String>{};
  return (request) async {
    if (request.method != 'GET' ||
        request.headers.get('upgrade')?.toLowerCase() != 'websocket') {
      return Response.text('WebSocket upgrade required', status: 404);
    }
    final origin = request.headers.get('origin');
    if (origin != null &&
        origins != null &&
        !origins.contains(origin.toLowerCase())) {
      return Response.text('Origin refused', status: 403);
    }
    final tokens = request.headers
        .get('connection')
        ?.toLowerCase()
        .split(',')
        .map((v) => v.trim());
    final key = request.headers.get('sec-websocket-key');
    var validKey = false;
    try {
      validKey = key != null && base64.decode(key).length == 16;
    } on FormatException {
      /* refused below */
    }
    if (tokens?.contains('upgrade') != true ||
        !validKey ||
        request.headers.get('sec-websocket-version') != '13') {
      return Response.text('Invalid WebSocket handshake', status: 400);
    }
    String? protocol;
    for (final value
        in (request.headers.get('sec-websocket-protocol') ?? '').split(',')) {
      if (supported.contains(value.trim())) {
        protocol = value.trim();
        break;
      }
    }
    return WebSocketResponse(
      onConnection,
      protocol,
      maxMessageSize,
      pingInterval,
    );
  };
}