Skip to content

Commit ac6e18c

Browse files
committed
fix(client-ws-transport): Handle WebSocket close code 1009 (Message Too Big) (#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 af92999 commit ac6e18c

File tree

1 file changed

+26
-3
lines changed
  • packages/cubejs-client-ws-transport/src

1 file changed

+26
-3
lines changed

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
/**
@@ -138,10 +140,10 @@ class WebSocketTransport implements ITransport<WebSocketTransportResult> {
138140
ws.sendMessage({ authorization: this.authorization });
139141
};
140142

141-
ws.onmessage = (event: any) => {
143+
ws.onmessage = (event: MessageEvent) => {
142144
ws.lastMessageTimestamp = new Date();
143145

144-
const message: any = JSON.parse(event.data);
146+
const message: any = JSON.parse(event.data.toString());
145147
if (message.handshake) {
146148
ws.reconcile();
147149
ws.reconcileTimer = setInterval(() => {
@@ -160,16 +162,37 @@ class WebSocketTransport implements ITransport<WebSocketTransportResult> {
160162
ws.sendQueue();
161163
};
162164

163-
ws.onclose = () => {
165+
ws.onclose = (event: CloseEvent) => {
164166
if (ws && ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) {
165167
ws.close();
166168
}
169+
167170
if (ws.reconcileTimer) {
168171
clearInterval(ws.reconcileTimer);
169172
ws.reconcileTimer = null;
170173
}
174+
171175
if (this.ws === ws) {
172176
this.ws = null;
177+
178+
// Close code 1009: Message Too Big. Server rejects messages exceeding maxPayload
179+
// without decoding. Retrying would cause an infinite loop, so we notify subscribers
180+
// and clear subscriptions instead.
181+
if (event?.code === 1009) {
182+
const error = new WebSocketTransportResult({
183+
status: 413,
184+
message: { error: event?.reason || 'WebSocket message too big' }
185+
});
186+
187+
Object.values(this.messageIdToSubscription).forEach(sub => {
188+
sub.callback(error);
189+
});
190+
191+
this.messageIdToSubscription = {};
192+
193+
return;
194+
}
195+
173196
if (Object.keys(this.messageIdToSubscription).length) {
174197
this.initSocket();
175198
}

0 commit comments

Comments
 (0)