dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.09k stars 1.56k forks source link

WebSocket can send and receive messages despite being closed #25536

Open nex3 opened 8 years ago

nex3 commented 8 years ago

If a WebSocket client's connection is closed by the server after its subscription has been canceled, it's still able to send messages. I haven't read the spec or examined the protocol-level interactions in detail, but this seems wrong.

What's more, Dart's WebSocket server will also receive this message—despite having called both WebSocket.close() and HttpServer.close(). This is clearly wrong, since the documentation of WebSocket.close() says that it "closes the WebSocket connection".

Here's a reproduction:

import 'dart:async';
import 'dart:io';

main() async {
  var server = await HttpServer.bind('localhost', 0);
  server.transform(new WebSocketTransformer()).listen((socket) {
    socket.listen((msg) {
      print("got $msg");

      // As soon as the server's socket receives a message, close the server and
      // the socket. Once these complete there should be no server-side sockets
      // open at all.
      socket.close().then((_) => print("socket closed"));
      server.close().then((_) => print("server closed"));
    });
  });

  var ws = await WebSocket.connect('ws://localhost:${server.port}');

  // Create and cancel a subscription.
  ws.listen(null).cancel();

  // Send a message to the server that will cause it to close the WebSocket
  // connection.
  ws.add("foo");

  // Give the server time to shut down.
  await new Future.delayed(new Duration(seconds: 1));

  // Try to send another message.
  ws.add("bar");
}

I reproduced this as of 77101d63e3c661957b7829dd96d6b4324da0e768.

I'd expect the socket to continue listening to the server behind-the-scenes even after the subscription is cancelled, so that it can determine when the connection is closed.

NatoBoram commented 6 years ago

I can confirm. Moreover, WebSocket.readyState always returns WebSocket.OPEN. https://github.com/dart-lang/sdk/issues/32876

mskv commented 5 years ago

I can confirm as well. I have just stumbled upon it while testing how my Android Flutter app behaves after turning on and off the airplane mode. The socket becomes unusable with no indication of the problem. As mentioned, even the readyState is OPEN.

mskv commented 5 years ago

Actually, my case described above seems to be resolved by reacting to ws.done. I can re-establish the connection then after an offline period.