Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random disconnects with 1006 error in Firefox #1436

Closed
1 task done
hansmiller75a opened this issue Aug 23, 2018 · 15 comments
Closed
1 task done

Random disconnects with 1006 error in Firefox #1436

hansmiller75a opened this issue Aug 23, 2018 · 15 comments

Comments

@hansmiller75a
Copy link

hansmiller75a commented Aug 23, 2018

  • I've searched for any related issues and avoided creating a duplicate issue.

Possibly related to, though couldn't confirm: socketio/socket.io#2016

Description

I experience random disconnects on a remote connection to a server.

The disconnects do not happen when I run the code locally or remotely in Chromium. They only occur when running the code remotely in Firefox.

I have filed a bug report with Firefox (https://bugzilla.mozilla.org/show_bug.cgi?id=1478157).

However, I do not experience these disconnects when I switch the library to socket.io, which is the reason I'm also filing a bug report here.

Reproducible in:

version:
Node.js version(s): 10.9.0
OS version(s): Linux computer 4.18.3-arch1-1-ARCH
Firefox 62.0.2 on archlinux

Steps to reproduce:

  1. Download and extract attached testcase
  2. Run npm install
  3. Generate a private key and ssl certificate under localhost.key and localhost.crt (or modify the code to run insecurely)
  4. If running on server/domain, modify the "localhost" string in the last line of index.js to match the domain name
  5. Run node index.js

Expected result:

When running the code on a remote server, you shouldn't experience disconnects.

Actual result:

I experience random disconnects with this output:

  • onopen
    open { target: WebSocket, isTrusted: true, eventPhase: 0, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 208, cancelBubble: false, originalTarget: WebSocket, … }
    mydomain.com:8443:45:9
    The connection to wss://mydomain.com:8443/ was interrupted while the page was loading. mydomain.com:8443:9:16
    onerror
    error { target: WebSocket, isTrusted: true, currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 191826, cancelBubble: false, … }
    mydomain.com:8443:25:5
    onclose
    close { target: WebSocket, isTrusted: true, wasClean: false, code: 1006, reason: "", currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false, defaultPrevented: false, … }
    mydomain.com:8443:20:5
    on open
    open { target: WebSocket, isTrusted: true, currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 192111, cancelBubble: false, … }

Attachments:

testcase.tar.gz

@lpinca
Copy link
Member

lpinca commented Aug 23, 2018

I can't reproduce, here is my code:

const WebSocket = require('ws');
const http = require('http');

const data = `<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <script>
      (function () {
        var ws = new WebSocket('ws://localhost:8080');

        ws.onopen = function () {
          console.log('open');
          ws.send(JSON.stringify({ data: 'payload' }));
        };
        ws.onerror = function (evt) {
          console.log('error', evt);
        };
        ws.onclose = function (evt) {
          console.log('close', evt.code);
        }
      })();
    </script>
  </body>
</html>`;

const server = http.createServer();

server.on('request', (req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.end(data);
});

const wss = new WebSocket.Server({ server });

server.listen(8080, () => console.log('Listening on *:8080'));

Tested on

  • Node.js v10.9.0.
  • DigitalOcean droplet with CentOS 7.
  • Firefox 61.0.2 on Windows 10.

@hansmiller75a
Copy link
Author

That's weird, using your code, I get the same error.

open mydomain.com:8080:12:11
The connection to ws://mydomain.com:8080/ was interrupted while the page was loading. mydomain.com:8080:9:17
error
error { target: WebSocket, isTrusted: true, currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 200482, cancelBubble: false, … }
mydomain.com:8080:16:11
close 1006

This happened after around 5 minutes.

@lpinca
Copy link
Member

lpinca commented Aug 24, 2018

The error message is indeed weird, the handshake succeeds, the open event is emitted, then you get

The connection to ... was interrupted while the page was loading.

which doesn't make much sense.

Try to periodically send some data using something like this https://github.com/websockets/ws#how-to-detect-and-close-broken-connections to see if the connection is close for timeout.

@lpinca
Copy link
Member

lpinca commented Sep 2, 2018

@hansmiller75a any update?

@hansmiller75a
Copy link
Author

hansmiller75a commented Sep 2, 2018

@lpinca I've made some tests using the code, and it appears that with pinging the socket every 30 seconds, I see no more disconnects (regardless if I use the test case or my actual application).

Would that suggest that the error is in Firefox? The reason I haven't experienced the disconnects with socket.io might be because they implicitly send those pings.

@lpinca
Copy link
Member

lpinca commented Sep 2, 2018

The reason I haven't experienced the disconnects with socket.io might be because they implicitly send those pings.

Yes, I think so.
I don't think the issue in Firefox, it's more likely to be a proxy between the browser and the server that closes the connection due to inactivity. It's indeed strange that it only happens with Firefox though.

@hansmiller75a
Copy link
Author

That's what I thought too, I originally had the nodejs app behind an nginx proxy. But even running the nodejs server directly on 443, I still get those disconnects.

And as said, I don't experience them in Chromium, with or without the nginx proxy...

@lpinca
Copy link
Member

lpinca commented Sep 2, 2018

No clue, try to use a different WebSocket server, like one written in Python, Go or whatever and see if the issue persists.

@lpinca
Copy link
Member

lpinca commented Sep 2, 2018

It might make sense to also try with a different version of Firefox.

@lpinca
Copy link
Member

lpinca commented Sep 23, 2018

Closing as I think this is not an issue in the lib. Please comment back if needed.

@lpinca lpinca closed this as completed Sep 23, 2018
@intpp
Copy link

intpp commented Nov 29, 2018

Reproduced with https://github.com/websockets/wscat, Chrome, Safari

@alexanderkhivrych
Copy link

Reproduced also with https://github.com/websockets/wscat Chrome

@cigzigwon
Copy link

I've observed this behavior before and I'm pretty sure Firefox is part of this issue because Chrome seems to work. It is possible that your back end needs to be re-tooled. I think if you are using the express server with socket.io or websocket it seems to handle this. In Elixirlang you may be missing some code that adhere's to websocket spec. I suggest avoiding WS back ends like PHP but have not worked with them. I see above that some languages may not handle this very well. Try Erlang or Elixir and you can gain a better understanding of this world.

@cigzigwon
Copy link

cigzigwon commented Mar 7, 2019

@lpinca I second that this is not an issue with socket.io back ends. It is the handling of ping requests in Mozilla. I suspect that alternative back end solution libs are outdated. You need to rev up your backends to something new. Try Elixirlang.

Here is a bare minimum spec for a handler. This is an Elixirlang case function to send messages back through a looping mechanism after a connected client sends a message. FYI. An underscore in Elixir is a match all. Elixir uses pattern matching to run a case function.

case conn |> Socket.Web.recv! do
  {:text, text} ->
    # handle text (one message)
  {:fragmented, :text, text} ->
    # handle frags (large docs)
  {:fragmented, :continuation, text} ->
    # continue frags (large docs)
  {:fragmented, :end, text} ->
    # end frags (large docs)
  {:ping, "PING"} ->
    # send a pong reply
  {:ping, _ } ->
    # handle edge cases (Is this the culprit w/Mozilla????) <--- BAD MOZILLA
  {:close, :abnormal, nil} ->
    # abnormal closes (server case)
  {:close, :going_away, ""} ->
    # going away (server case)
  :close ->
    # any close event
end

@cigzigwon
Copy link

cigzigwon commented Mar 7, 2019

@intpp and @alexanderkhivrych Does your server implement PING handling and reply with PONG?
Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in response, unless it already received a Close frame.
https://tools.ietf.org/html/rfc6455#section-5.5.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants