StreamingApiServerService: handle websocket errors from client gracefully
$ nc -C tarta.nabijaczleweli.xyz 12122
GET /streaming?_t=1752534314122 HTTP/1.1
Host: tarta.nabijaczleweli.xyz:12122
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
the parameters almost don't matter so long as the server
replies with an upgrade, then press enter once or twice,
at which point the server will have crashed after
INFO 1 [core nest] NestFactory: Starting Nest application...
ERR * [core] Uncaught exception (uncaughtException): RangeError: Invalid WebSocket frame: invalid opcode 13
at Receiver.getInfo (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:311:26)
at Receiver.startLoop (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:155:16)
at Receiver._write (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:94:10)
at writeOrBuffer (node:internal/streams/writable:572:12)
at _write (node:internal/streams/writable:501:10)
at Writable.write (node:internal/streams/writable:510:10)
at Socket.socketOnData (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/websocket.js:1355:35)
at Socket.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
at Readable.push (node:internal/streams/readable:392:5)
at TCP.onStreamRead (node:internal/stream_base_commons:189:23) {
code: 'WS_ERR_INVALID_OPCODE',
[Symbol(status-code)]: 1002
}
INFO * [core] The process is going to exit with code 1
node:events:496
throw er; // Unhandled 'error' event
^
RangeError: Invalid WebSocket frame: invalid opcode 13
at Receiver.getInfo (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:311:26)
at Receiver.startLoop (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:155:16)
at Receiver._write (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/receiver.js:94:10)
at writeOrBuffer (node:internal/streams/writable:572:12)
at _write (node:internal/streams/writable:501:10)
at Writable.write (node:internal/streams/writable:510:10)
at Socket.socketOnData (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/websocket.js:1355:35)
at Socket.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
at Readable.push (node:internal/streams/readable:392:5)
at TCP.onStreamRead (node:internal/stream_base_commons:189:23)
Emitted 'error' event on WebSocket instance at:
at Receiver.receiverOnError (/srv/Sharkey/node_modules/.pnpm/ws@8.18.1_bufferutil@4.0.9_utf-8-validate@6.0.5/node_modules/ws/lib/websocket.js:1199:15)
at Receiver.emit (node:events:518:28)
at emitErrorNT (node:internal/streams/destroy:170:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
code: 'WS_ERR_INVALID_OPCODE',
[Symbol(status-code)]: 1002
}
Node.js v22.14.0
ELIFECYCLE Command failed with exit code 1.
This works through some reverse proxies (HAProxy, Caddy),
but not through others (Cloudflare, nginx, Apache(?))
Instead, just hang up if the client violates protocol
Fixes https://101010.pl/@nabijaczleweli/114854334401159070
This commit is contained in:
parent
05a499ac55
commit
d954b8d138
1 changed files with 9 additions and 0 deletions
|
|
@ -12,6 +12,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import type { UsersRepository, MiAccessToken, MiUser, NoteReactionsRepository, NotesRepository, NoteFavoritesRepository } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { Keyed, RateLimit } from '@/misc/rate-limit-utils.js';
|
||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
|
|
@ -20,6 +21,7 @@ import { UserService } from '@/core/UserService.js';
|
|||
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
|
||||
import { getIpHash } from '@/misc/get-ip-hash.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import { SkRateLimiterService } from '@/server/SkRateLimiterService.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { AuthenticateService, AuthenticationError } from './AuthenticateService.js';
|
||||
|
|
@ -38,6 +40,7 @@ export class StreamingApiServerService implements OnApplicationShutdown {
|
|||
#connectionsByClient = new Map<string, Set<WebSocket.WebSocket>>(); // key: IP / user ID -> value: connection
|
||||
#cleanConnectionsIntervalId: NodeJS.Timeout | null = null;
|
||||
readonly #globalEv = new EventEmitter();
|
||||
#logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redisForSub)
|
||||
|
|
@ -69,6 +72,7 @@ export class StreamingApiServerService implements OnApplicationShutdown {
|
|||
private config: Config,
|
||||
) {
|
||||
this.redisForSub.on('message', this.onRedis);
|
||||
this.#logger = loggerService.getLogger('streaming', 'coral');
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -222,6 +226,11 @@ export class StreamingApiServerService implements OnApplicationShutdown {
|
|||
}
|
||||
});
|
||||
|
||||
ws.once('error', (e) => {
|
||||
this.#logger.error(`Unhandled error in Streaming Api: ${renderInlineError(e)}`);
|
||||
ws.terminate();
|
||||
});
|
||||
|
||||
this.#wss.emit('connection', ws, request, {
|
||||
stream, user, app,
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue