upgradeToWebSocket static method

Future<WebSocket> upgradeToWebSocket(
  1. HttpRequest request, [
  2. dynamic protocolSelector(
    1. List<String> protocols
    )?,
  3. bool? useStandardWebSocket
])

Implementation

static Future<WebSocket> upgradeToWebSocket(
  HttpRequest request, [
  Function(List<String> protocols)? protocolSelector,
  bool? useStandardWebSocket,
]) {
  useStandardWebSocket ??= enableStandardWebSocket;

  if (useStandardWebSocket) {
    return WebSocketTransformer.upgrade(
      request,
      protocolSelector: protocolSelector,
    );
  }

  var response = request.response;
  if (!WebSocketTransformer.isUpgradeRequest(request)) {
    // Send error response.
    response
      ..statusCode = HttpStatus.badRequest
      ..close();
    return Future.error(
      WebSocketException('Invalid WebSocket upgrade request'),
    );
  }

  Future<WebSocket> upgrade(String? protocol) {
    // Send the upgrade response.
    response
      ..statusCode = HttpStatus.switchingProtocols
      ..headers.add(HttpHeaders.connectionHeader, 'Upgrade')
      ..headers.add(HttpHeaders.upgradeHeader, 'websocket');
    var key = request.headers.value('Sec-WebSocket-Key')!;
    var accept = base64.encode(
      sha1.convert('$key$_webSocketGUID'.codeUnits).bytes,
    );
    response.headers.add('Sec-WebSocket-Accept', accept);
    if (protocol != null) {
      response.headers.add('Sec-WebSocket-Protocol', protocol);
    }
    response.headers.contentLength = 0;
    return response.detachSocket().then((socket) {
      socket.setOption(SocketOption.tcpNoDelay, _tcpNoDelay);
      return WebSocket.fromUpgradedSocket(
        socket,
        protocol: protocol,
        serverSide: true,
      );
    });
  }

  var protocols = request.headers['Sec-WebSocket-Protocol'];
  if (protocols != null && protocolSelector != null) {
    // The suggested protocols can be spread over multiple lines, each
    // consisting of multiple protocols. To unify all of them, first join
    // the lists with ', ' and then tokenize.
    protocols = HttpHelper.tokenizeFieldValue(protocols.join(', '));
    return Future(
      () => protocolSelector(protocols!)
          .then((dynamic protocol) {
            if (!protocols!.contains(protocol)) {
              throw WebSocketException(
                'Selected protocol is not in the list of available protocols',
              );
            }
            return protocol;
          })
          .catchError((dynamic error) {
            response
              ..statusCode = HttpStatus.internalServerError
              ..close();
            throw error;
          })
          .then((dynamic result) {
            if (result is String) {
              return upgrade(result);
            }
            return null;
          })
          .then((WebSocket socket) {
            return socket;
          }),
    );
  } else {
    return upgrade(null);
  }
}