Skip to content

Websocket RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear #1354

Closed

Description

@ztnark
  • [ x] I've searched for any related issues and avoided creating a duplicate issue.

Description

I'm using ws as a client in my node application, and when I attempt to connect to the host, the connection is closed with the error 'Websocket RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear'.

It is worth noting that the connection is successful to a different host, but I believe this is a client issue?

It's also worth noting that faye-websocket functions correctly in the same situation.

Reproducible in:

version: 5.1.1
Node.js version(s): 8.9.4
OS version(s): Windows 7 Professional v6.1 (build 7601)

Steps to reproduce:

  1. Run the following code inside of a Node Application:
const WebSocket = require('ws')

const ws = new WebSocket('ws://site:8765/ws')

ws.on('message', data => {
  console.log(data)
})
ws.on('error', err => { console.log(err) })
ws.on('close', () => { console.log('close') })

Activity

  1. lpinca commented on Apr 6, 2018

    @lpinca
    Member

    It might be a bug that has been recently fixed in nodejs/node#17806 but I think not yet backported to Node.js 8.

    Try to use Node.js 9. If the issue persists please post the received data on the socket. You can do that by attaching a listener for the 'data' event on the internal socket.

    const ws = new WebSocket('ws://site:8765/ws');
    
    ws.on('open', function () {
      ws._socket.on('data', console.log);
    });
  2. lpinca commented on Apr 10, 2018

    @lpinca
    Member

    @ztnark any update?

  3. jeroenvollenbrock commented on Apr 11, 2018

    @jeroenvollenbrock

    Should be resolved in the next Node.js 8 version as well, presumably 8.11.2 :)

  4. ztnark commented on Apr 11, 2018

    @ztnark
    Author
  5. ztnark commented on Apr 12, 2018

    @ztnark
    Author

    @lpinca, good news. I can confirm that upgrading to Node.js 9 (11.1) fixes this issue. I can also test on 8.11.2, when released. Thank you.

  6. lpinca commented on Apr 13, 2018

    @lpinca
    Member

    I'm closing then. Please reopen if the issue persists.
    Thank you.

  7. danielmurray commented on Jun 6, 2018

    @danielmurray

    Howdy all,

    As of today, electron is currently running node@8.9.3 in it's main process. So the solution of upgrading the local node version is not a viable option for electron app developers.

    Dan

  8. Turbo87 commented on Jul 2, 2018

    @Turbo87

    FWIW I'm hitting the same issue with Node 10 too, but I would expect that this is a server-side issue, with a server sending a frame with those flags that should actually not be set.

  9. ashbrener commented on Jul 12, 2018

    @ashbrener

    I am experiencing a similar issue on node v8.11.3 and v10.6.0

    node_modules/ws/lib/receiver.js:167
          return error(RangeError, 'RSV1 must be clear', true, 1002);
                 ^
    RangeError: Invalid WebSocket frame: RSV1 must be clear
        at Receiver.getInfo (/node_modules/ws/lib/receiver.js:167:14)
        at Receiver.startLoop (/node_modules/ws/lib/receiver.js:121:22)
        at Receiver._write (/node_modules/ws/lib/receiver.js:69:10)
        at doWrite (_stream_writable.js:397:12)
        at writeOrBuffer (_stream_writable.js:383:5)
        at Receiver.Writable.write (_stream_writable.js:290:11)
        at TLSSocket.socketOnData (/node_modules/ws/lib/websocket.js:795:35)
        at emitOne (events.js:116:13)
        at TLSSocket.emit (events.js:211:7)
        at addChunk (_stream_readable.js:263:12)
        at readableAddChunk (_stream_readable.js:250:11)
        at TLSSocket.Readable.push (_stream_readable.js:208:10)
        at TLSWrap.onread (net.js:597:20)
    

    Have wrapped ws.send() in a try / catch as well as set perMessageDeflate=false in the client constructor options.

  10. lpinca commented on Jul 12, 2018

    @lpinca
    Member

    Are you getting it on the client or server? If it is on the server it's possible that a malicious client is sending faulty frames intentionally.

    If it's on client instead, you can try to log the received data

    ws.on('open', function () {
      ws._socket.prependListener('data', function (chunk) {
        console.log(chunk.toString('hex'));
      });
    });
  11. ashbrener commented on Jul 12, 2018

    @ashbrener

    @lpinca thank you for the fast response. This advice was most helpful, the error is on the client and I added the listener as you suggested.

    This led me to find what I think could be the cause. The server (which also uses ws) is aborting the handshake based on a certain condition (a custom override in our app) using a copy of the abortHandshake function.

    And so it is writing the following data to the socket:

    HTTP/1.1 401 Unauthorized
    Connection: close
    Content-type: text/html
    Content-Length: 12
    
    Unauthorized

    ... which the client receives and throws the RangeError on. Does this make sense?

  12. 4 remaining items

  13. lpinca commented on Jul 12, 2018

    @lpinca
    Member

    You probably have your own reasons to do that (overriding handleUpgrade) but the verifyClient option can be used for this.

  14. tgraupmann commented on Feb 7, 2021

    @tgraupmann

    FYI, this issue still reproduces on both WSL2 and Windows 10 for Node v14.15.4.

    I have a sample client that can crash a WS server instantly.

    I'm using pretty much the minimal sample - Server: https://github.com/tgraupmann/NodeJS_WS/blob/master/app.js

    This worked fine sending JSON payloads. I'm testing a C client with binary payloads which crash the server.

    C:\Public\NodeJS_WS>node app.js
    events.js:292
          throw er; // Unhandled 'error' event
          ^
    
    RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear
        at Receiver.getInfo (C:\Public\NodeJS_WS\node_modules\←[4mws←[24m\lib\receiver.js:171:14)
        at Receiver.startLoop (C:\Public\NodeJS_WS\node_modules\←[4mws←[24m\lib\receiver.js:131:22)
        at Receiver._write (C:\Public\NodeJS_WS\node_modules\←[4mws←[24m\lib\receiver.js:78:10)
    ←[90m    at writeOrBuffer (internal/streams/writable.js:358:12)←[39m
    ←[90m    at Receiver.Writable.write (internal/streams/writable.js:303:10)←[39m
        at Socket.socketOnData (C:\Public\NodeJS_WS\node_modules\←[4mws←[24m\lib\websocket.js:900:35)
    ←[90m    at Socket.emit (events.js:315:20)←[39m
    ←[90m    at addChunk (internal/streams/readable.js:309:12)←[39m
    ←[90m    at readableAddChunk (internal/streams/readable.js:284:9)←[39m
    ←[90m    at Socket.Readable.push (internal/streams/readable.js:223:10)←[39m
    Emitted 'error' event on WebSocket instance at:
        at Receiver.receiverOnError (C:\Public\NodeJS_WS\node_modules\←[4mws←[24m\lib\websocket.js:805:13)
    ←[90m    at Receiver.emit (events.js:315:20)←[39m
    ←[90m    at emitErrorNT (internal/streams/destroy.js:106:8)←[39m
    ←[90m    at emitErrorCloseNT (internal/streams/destroy.js:74:3)←[39m
    ←[90m    at processTicksAndRejections (internal/process/task_queues.js:80:21)←[39m {
      [←[32mSymbol(status-code)←[39m]: ←[33m1002←[39m
    }
    
    C:\Public\NodeJS_WS>node --version
    v14.15.4
    

    Also reproduced initially on WSL2.

    RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear
        at Receiver.getInfo (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/receiver.js:171:14)
        at Receiver.startLoop (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/receiver.js:131:22)
        at Receiver._write (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/receiver.js:78:10)
        at doWrite (_stream_writable.js:415:12)
        at writeOrBuffer (_stream_writable.js:399:5)
        at Receiver.Writable.write (_stream_writable.js:299:11)
        at Socket.socketOnData (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/websocket.js:900:35)
        at Socket.emit (events.js:198:13)
        at addChunk (_stream_readable.js:288:12)
        at readableAddChunk (_stream_readable.js:269:11)
    Emitted 'error' event at:
        at Receiver.receiverOnError (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/websocket.js:805:13)
        at Receiver.emit (events.js:198:13)
        at errorOrDestroy (internal/streams/destroy.js:107:12)
        at onwriteError (_stream_writable.js:430:5)
        at onwrite (_stream_writable.js:461:5)
        at Receiver.startLoop (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/receiver.js:152:5)
        at Receiver._write (/home/tgraupmann/NodeJS_WS/node_modules/ws/lib/receiver.js:78:10)
        [... lines matching original stack trace ...]
        at Receiver.Writable.write (_stream_writable.js:299:11)
    tgraupmann@polaris:~/NodeJS_WS$ node --version
    v10.19.0
    

    The offending C client code looks like this:

    _libwsclient_write(_sWebSocketClient, refFrame._mData, FChromaStreamRefFrame_DATA_SIZE);
    
    The buffer is a simple unsigned char* and I'm passing the size. 
    

    This is the client library that I'm using - https://github.com/tgraupmann/libwsclient

    It's entirely that I'm using the websocket API incorrectly, and will take any recommendations for a better client that handles binary payloads in pure "C".

    That said, it's still able to crash the server though its incorrect use.

    I also have a direct repro for any that are interested in following up.

  15. lpinca commented on Feb 7, 2021

    @lpinca
    Member

    'error' events must be handled.

    wss.on('connection', function(ws) {
      ws.on('error', console.error);
    });
  16. tgraupmann commented on Feb 7, 2021

    @tgraupmann

    'error' events must be handled.

    wss.on('connection', function(ws) {
      ws.on('error', console.error);
    });

    That's all it was. The server just needed an error handler to avoid crashing. And now it logs errors without exiting. Thanks!

  17. crisdosaygo commented on Oct 23, 2022

    @crisdosaygo

    I'm seeing this in node v18.8.0 when connecting from a Safari client (latest Safari, latest iOS 16.3). Hard to reproduce: it does not happen on first connect, but after reloading the page. Yet after a couple of reloads it works, then breaks again.

    Sorry could not provide more details right now. Weird bug...don't even know if it comes from the ws library, just posting here because I found this issue while searching for answers

    More details

    It's probably been covered in this issue or elsewhere in ws already but I went looking around and it seems:

    According to RFC6455:

    RSV1, RSV2, RSV3: 1 bit each

    MUST be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint MUST Fail the WebSocket Connection.

    So, at least in my case, the Safari client seems to be incorrectly (?) setting these bits.

    It may the wrong fit for ws (and there may be valid security concerns around not doing this), but a possible guide here might be the robustness principle: "be conservative in what you send, be liberal in what you accept"

    If that could be possible, then adding a ws API (maybe in the form of an optional strictProtocol flag), like:

     const wss = new WebSocketServer({
          server,
          perMessageDeflate: false, 
          strictProtocol: false,
        });

    to permit these "non-conforming" messages could be a way to still serve clients that make these errors.

  18. crisdosaygo commented on Oct 23, 2022

    @crisdosaygo

    'error' events must be handled.

    wss.on('connection', function(ws) {
      ws.on('error', console.error);
    });

    That's all it was. The server just needed an error handler to avoid crashing. And now it logs errors without exiting. Thanks!

    @tgraupmann I have an error handler, but my websocket closes after showing this RangeError.

  19. lpinca commented on Oct 23, 2022

    @lpinca
    Member

    @crisdosyago the spec specifically says that

    the receiving endpoint MUST Fail the WebSocket Connection.

    I'm strongly against adding a strictProtocol option or anything like that. A lot of WebSocket implementation do not even inform the user of the error. They just close the connection silently.

    Also, it is not the first time that Safari introduces bugs like this. See #1922.

  20. crisdosaygo commented on Oct 23, 2022

    @crisdosaygo

    Understood @lpinca I know you don't want to dirty this library with irregularities or tolerances of those. Thank you for your consideration of this idea, it sounds like you've given this some serious thought and like you believe it's the right choice to not include here because doing so would mean your library would no longer meet the standard of quality you're trying to keep. I trust you. Thank you for your information--including on the other bug (how interesting! that Safari!)--and thanks for the amazing work on this great library!

  21. misi commented on Dec 8, 2022

    @misi

    I have set proper error handler on the websocket
    wss.on('connection', function(ws) { ws.on('error', console.error); });
    I experience that in some cases I see the log, but in rear cases
    (Probably ws error handler not working properly or removed?) it does not catch the error and node process exits and it kills my app.
    running ws version: 8.11.0 & node16

    @lpinca can you help me with few hints.
    Where should I start to search the root cause of the issue?
    Thanks..

    node:events:491
          throw er; // Unhandled 'error' event
          ^
    RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear
        at Receiver.getInfo (/opt/my/src/node_modules/ws/lib/receiver.js:176:14)
        at Receiver.startLoop (/opt/my/src/node_modules/ws/lib/receiver.js:136:22)
        at Receiver._write (/opt/my/node_modules/ws/lib/receiver.js:83:10)
        at writeOrBuffer (node:internal/streams/writable:391:12)
        at _write (node:internal/streams/writable:332:10)
        at Receiver.Writable.write (node:internal/streams/writable:336:10)
        at TLSSocket.socketOnData (/opt/my/src/node_modules/ws/lib/websocket.js:1272:35)
        at TLSSocket.emit (node:events:513:28)
        at TLSSocket.emit (node:domain:489:12)
        at addChunk (node:internal/streams/readable:315:12)
    Emitted 'error' event on WebSocket instance at:
        at Receiver.receiverOnError (/opt/my/src/node_modules/ws/lib/websocket.js:1158:13)
        at Receiver.emit (node:events:513:28)
        at Receiver.emit (node:domain:489:12)
        at emitErrorNT (node:internal/streams/destroy:157:8)
        at emitErrorCloseNT (node:internal/streams/destroy:122:3)
        at processTicksAndRejections (node:internal/process/task_queues:83:21) {
      code: 'WS_ERR_UNEXPECTED_RSV_2_3',
      [Symbol(status-code)]: 1002
    }
    
  22. lpinca commented on Dec 8, 2022

    @lpinca
    Member

    Probably ws error handler not working properly or removed?

    Yes, make sure that the 'error' event listener is not removed before the 'close' event is emitted.

  23. misi commented on Dec 12, 2022

    @misi

    Yes removed error handler in tear down, and it caused it. Thanks!

  24. marcolanaro commented on Dec 16, 2022

    @marcolanaro

    @misi Can you please provide a code example or reference for this use case?

  25. atanasyordanov21 commented on Jun 19, 2023

    @atanasyordanov21

    I was also struggling with such an issue for some time. Tried several different web socket clients, and always the same. Then I started breaking down my code, and it turned out that the following line was causing the issue in my case:
    request.socket.setEncoding("utf8");
    request comes from here:

    wss.on('connection', (ws, request) => {
    ...
    });
    
    
  26. smallCF commented on Jul 13, 2023

    @smallCF

    Hello author;

    Using node as a program to use ws, will inconsistent time between the user and server in the same time zone result in the issue of RSV2 and RSV3 must be clear?

    The node service on my end is installed using the Docker method

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions