Since WebSocket in Dart does not directly allow to set a SecurityContext (which I need for certificate checks), I would like to establish the connection with a SecureSocket instance, and then use the WebSocket.fromUpgradedSocket constructor to create a WebSocket instance from it.

This idea was originally suggested here.

However, I do not get it to work with the following code (while I want wss, not even ws works):

sock = await Socket.connect('ws://echo.websocket.org', 80);
socket = WebSocket.fromUpgradedSocket(sock, serverSide: false);
socket.listen(myListener);
// Send some dummy data
var list = utf8.encode("hello");
var data = list is Uint8List ? list : Uint8List.fromList(list);
socket.add(data);

Here sock is of type Socket, socket of type WebSocket, and myListener is a function that prints some debug statements when a message was received. I do not get an error, but neither do I get into the listener - which I do when I replace the first two lines with this one:

socket = await WebSocket.connect('ws://echo.websocket.org');    

I assume that the problem is that my Socket 'sock' is not upgraded, while the WebSocket source code for the mentioned constructor clearly states: 'Creates a WebSocket from an already-upgraded socket.'.

So my question is, is it possible with the existing Dart classes to upgrade a client (Secure-)Socket to an upgraded (Secure-)Socket? (which would then allow to transform it to a WebSocket instance)


Solution 1: Richard Heap

Use the HttpClient to establish the initial http(s) connection and then detach the socket. Here's an example with http. You should be able to adapt to https. Note how the initial connection is made over http, but upgraded by adding the appropriate request headers. (You'll need to adapt the headers to the security scheme required by your websocket server.)

  Random r = new Random();
  String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));

  HttpClient client = HttpClient(/* optional security context here */);
  HttpClientRequest request = await client.get('echo.websocket.org', 80,
      '/foo/ws?api_key=myapikey'); // form the correct url here
  request.headers.add('Connection', 'upgrade');
  request.headers.add('Upgrade', 'websocket');
  request.headers.add('sec-websocket-version', '13'); // insert the correct version here
  request.headers.add('sec-websocket-key', key);

  HttpClientResponse response = await request.close();
  // todo check the status code, key etc
  Socket socket = await response.detachSocket();

  WebSocket ws = WebSocket.fromUpgradedSocket(
    socket,
    serverSide: false,
  );