sockjs-client: xhr_streaming infinite loop after connection closed
Steps to reproduce:
- Turn WebSockets off in NodeJS server (
websocket: false
in options); - On the server, close all SockJS connections after a delay of 500 ms using
conn.close(1000, 'init_message_timeout')
(the exact code and message don’t matter); - Connect to that server using SockJS
1.0.1
(latest) or0.3.4
from the latest Chrome.
During the first 500 ms, the connection stays alive. After that, it gets closed as expected. However, the xhr_streaming
transport starts an infinite loop: it tries to connect to the server, then SockJS server (not the app logic) immediately closes that connection with the code/reason provided in the step 2, and, after that, xhr_streaming
attempts to connect again, and so on:
Here is HTTP log from the server:
This infinite loop takes significant amount of CPU on the client (up to 70%) and on the server and load balancers, effectively causing DDOS when there are multiple such forcefully-closed clients.
It seems to me that xhr_streaming
should not attempt to reconnect after it gets user-provided close reason from the server. Or am I misunderstanding something?
This issue hits us in production, and we need to resolve it as fast as possible.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 36 (4 by maintainers)
Still having this issue even on 1.1.2.
I got this because of my shadowsocks, I turned it off and no more errors.
Here is our workaround for this issue:
In our case, loop was triggered by (occasional) initialization timeout in xhr-polling transport. After the timeout, function _transportTimeout calls _transportClose, and _transportClose removes all listeners from transport, however, transport remains active. When transport receives message from spring with close request (like c[3000,Go away!]), no one will process this message (because there are no listeners!), and transport will loop (because response code is 200).
Update: I see this is already fixed in master, but not in 1.1.4
Same problem with sockjs 1.1.4, spring boot websocket
Hey folks, can you try 1.1.2 and let me know if you can still reproduce the problem?
I found where is the possible error. In polling.js i have see a special treatment when the close reason is ‘network’. When is network again call the function _scheduleReceiver(). When we reconnect the infinite loop occurs. I dont know what is the reason for this treatment but I could try this deleting the special treatment of ‘network’ and everything works correctly. @skozin Can you try?
if (!self.pollIsClosing) { if (reason === 'network') { self._scheduleReceiver(); } else { self.emit('close', code || 1006, reason); self.removeAllListeners(); } }
the workaround is:
if (!self.pollIsClosing) { self.emit('close', code || 1006, reason); self.removeAllListeners(); }
@brycekahle any chance of a release? I encountered this problem using sockjs via Primus (https://github.com/primus/primus/issues/635#issuecomment-38507835), hand-patching with https://github.com/sockjs/sockjs-client/commit/eef1957a4d8007a64e170a4bbb2c635e40d870b2 fixed it but it would be nice to be able to rebuild Primus and depend on an official sockjs version.