react-native: Websocket Wrong Control Frame [iOS]

There was already reported and it’s mark as resolved, see: #23825. But in fact this problem is still persist on iOS. After many investigation the problem comes from iOS RN WebSocket library.

Description

Server disconnect client on control packets, so if ping is disabled from server, problem disappear.

Error from server based on NodeJS

Invalid WebSocket frame: invalid payload length 126

This error appear when server send data and in parallel send control packets to client.

React Native version:

0.62.2

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 10
  • Comments: 15 (4 by maintainers)

Most upvoted comments

This bug has been around since 2015… how has it never become a priority?

This looks like the PONG frame sent by react-native is causing this problem.

“All control frames must have a payload length of 125 bytes or less” https://tools.ietf.org/html/rfc6455#page-36

In this scenario described by @vitalyrotari, the server-side is crashing due to what seems to be an invalid control frame being sent by the client.

@forbesgillikin we’re using graphql-ws and we’re having a similar problem, but it should be resolved in version 5.5.5 of graphql-ws: https://github.com/enisdenjo/graphql-ws/releases/tag/v5.5.5 The fix limits on JS side the max length of the close reason sent from the client.

For those using graphql-ws, the problem should not be related to ping/pong control frames, since the standard ping implementation of graphql-ws does not send any payload, and the react-native pong implementation just echoes it back (see here). The ping from react-native seems to send always an empty payload too (see here). Since with graphql-ws the problem seems to be caused by close frames with a reason that’s too long, it shouldn’t be really an issue, just an annoying error: the client already closed the connection, and a typical server closes it too when such an error happens.

The fix on the react-native side should be to do a check similar to this one when sending a frame in _sendFrameWithOpcode, and either truncate the message or report an error. The ws node library, for example, chooses to throw an error in this cases (see here).

This bug seems to have been fixed in this PR and optimized this PR in the original websocket implementation. The bug is caused by concurrent mutation of the _currentFrameData, which in the react-native copy of the original implementation should happen here. The fix should be as quick as copying the frame data like so inside _handleFrameWithData.

is this part of any react-native releases so far?

It was released on 0.68

I just disabled built-in ping-pong and made my custom implementation.

@knro Depends on your server. If you’re using ws on Node:

import WebSocket from 'ws';
...
const server = new WebSocket.Server({ ... });
server.on('connection', (socket, req) => {
  ...
  // Make sure to add this error handler here so your server doesn't crash
  // If you want, filter out the 126 error
  socket.on('error', (err) => console.error('socket error', err));
  ...
})

I continue to log this error in our production server just for fun and to get a sense of the scale of the problem. It happens constantly all day long. If we couldn’t prevent the crash our app would be unusable.