Response handle()

in lib/src/web_socket_handler.dart [28:84]


  Response handle(Request request) {
    if (request.method != 'GET') return _notFound();

    final connection = request.headers['Connection'];
    if (connection == null) return _notFound();
    final tokens =
        connection.toLowerCase().split(',').map((token) => token.trim());
    if (!tokens.contains('upgrade')) return _notFound();

    final upgrade = request.headers['Upgrade'];
    if (upgrade == null) return _notFound();
    if (upgrade.toLowerCase() != 'websocket') return _notFound();

    final version = request.headers['Sec-WebSocket-Version'];
    if (version == null) {
      return _badRequest('missing Sec-WebSocket-Version header.');
    } else if (version != '13') {
      return _notFound();
    }

    if (request.protocolVersion != '1.1') {
      return _badRequest('unexpected HTTP version '
          '"${request.protocolVersion}".');
    }

    final key = request.headers['Sec-WebSocket-Key'];
    if (key == null) return _badRequest('missing Sec-WebSocket-Key header.');

    if (!request.canHijack) {
      throw ArgumentError('webSocketHandler may only be used with a server '
          'that supports request hijacking.');
    }

    // The Origin header is always set by browser connections. By filtering out
    // unexpected origins, we ensure that malicious JavaScript is unable to fake
    // a WebSocket handshake.
    final origin = request.headers['Origin'];
    if (origin != null &&
        _allowedOrigins != null &&
        !_allowedOrigins!.contains(origin.toLowerCase())) {
      return _forbidden('invalid origin "$origin".');
    }

    final protocol = _chooseProtocol(request);
    request.hijack((channel) {
      final sink = utf8.encoder.startChunkedConversion(channel.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');

      _onConnection(
          WebSocketChannel(channel, pingInterval: _pingInterval), protocol);
    });
  }