Skip to content

Commit 5652f0f

Browse files
authored
fix(client-ws-transport): Handle WebSocket close code 1009 (Message Too Big) (cube-js#10246)
When the server has a low maxPayload limit, and the client sends an oversized message, the server closes the connection with code 1009 without decoding. Previously, the client would retry indefinitely, causing an infinite loop.
1 parent d0ce3f4 commit 5652f0f

1 file changed

Lines changed: 26 additions & 3 deletions

File tree

  • packages/cubejs-client-ws-transport/src

packages/cubejs-client-ws-transport/src/index.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import WebSocket from 'isomorphic-ws';
2+
3+
import type { CloseEvent, MessageEvent } from 'ws';
24
import type { ITransport, ITransportResponse } from '@cubejs-client/core';
35

46
class WebSocketTransportResult {
@@ -132,10 +134,10 @@ class WebSocketTransport implements ITransport<WebSocketTransportResult> {
132134
ws.sendMessage({ authorization: this.authorization });
133135
};
134136

135-
ws.onmessage = (event: any) => {
137+
ws.onmessage = (event: MessageEvent) => {
136138
ws.lastMessageTimestamp = new Date();
137139

138-
const message: any = JSON.parse(event.data);
140+
const message: any = JSON.parse(event.data.toString());
139141
if (message.handshake) {
140142
ws.reconcile();
141143
ws.reconcileTimer = setInterval(() => {
@@ -154,16 +156,37 @@ class WebSocketTransport implements ITransport<WebSocketTransportResult> {
154156
ws.sendQueue();
155157
};
156158

157-
ws.onclose = () => {
159+
ws.onclose = (event: CloseEvent) => {
158160
if (ws && ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) {
159161
ws.close();
160162
}
163+
161164
if (ws.reconcileTimer) {
162165
clearInterval(ws.reconcileTimer);
163166
ws.reconcileTimer = null;
164167
}
168+
165169
if (this.ws === ws) {
166170
this.ws = null;
171+
172+
// Close code 1009: Message Too Big. Server rejects messages exceeding maxPayload
173+
// without decoding. Retrying would cause an infinite loop, so we notify subscribers
174+
// and clear subscriptions instead.
175+
if (event?.code === 1009) {
176+
const error = new WebSocketTransportResult({
177+
status: 413,
178+
message: { error: event?.reason || 'WebSocket message too big' }
179+
});
180+
181+
Object.values(this.messageIdToSubscription).forEach(sub => {
182+
sub.callback(error);
183+
});
184+
185+
this.messageIdToSubscription = {};
186+
187+
return;
188+
}
189+
167190
if (Object.keys(this.messageIdToSubscription).length) {
168191
this.initSocket();
169192
}

0 commit comments

Comments
 (0)