Skip to content

Commit 56f2f5a

Browse files
feat(node-ws): allow custom http exception status code for node-ws (#1583)
* fix(1573): allow custom http exception status code for node-ws * update the changeset * chore: fix the lint errors --------- Co-authored-by: Yusuke Wada <yusuke@kamawada.com>
1 parent 03e1a2c commit 56f2f5a

File tree

4 files changed

+30
-4
lines changed

4 files changed

+30
-4
lines changed

.changeset/lazy-wasps-ask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hono/node-ws': minor
3+
---
4+
5+
Allow custom HTTPException in node-ws upgrade

packages/node-ws/src/index.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { serve } from '@hono/node-server'
44
import type { ServerType } from '@hono/node-server/dist/types'
55
import { Hono } from 'hono'
66
import { cors } from 'hono/cors'
7+
import { HTTPException } from 'hono/http-exception'
78
import type { WSMessageReceive } from 'hono/ws'
89
import { WebSocket } from 'ws'
910
import { createNodeWebSocket } from '.'
@@ -312,4 +313,20 @@ describe('WebSocket helper', () => {
312313
expect(clientWs).toBeTruthy()
313314
expect(wss.clients.size).toBe(1)
314315
})
316+
317+
it('Should allow for custom HTTPException status code', async () => {
318+
app.get(
319+
'/',
320+
upgradeWebSocket(() => {
321+
throw new HTTPException(401)
322+
})
323+
)
324+
const ws = new WebSocket('ws://localhost:3030/')
325+
await new Promise<void>((resolve) =>
326+
ws.on('unexpected-response', (_, response) => {
327+
expect(response.statusCode).toEqual(401)
328+
resolve()
329+
})
330+
)
331+
})
315332
})

packages/node-ws/src/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { Hono } from 'hono'
22
import { defineWebSocketHelper } from 'hono/ws'
3-
import type { UpgradeWebSocket, WSContext, WSEvents } from 'hono/ws'
3+
import type { UpgradeWebSocket, WSContext } from 'hono/ws'
44
import type { WebSocket } from 'ws'
55
import { WebSocketServer } from 'ws'
6+
import { STATUS_CODES } from 'node:http'
67
import type { IncomingMessage, Server } from 'node:http'
78
import type { Http2SecureServer, Http2Server } from 'node:http2'
89
import type { Duplex } from 'node:stream'
@@ -77,12 +78,12 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
7778
incoming: request,
7879
outgoing: undefined,
7980
}
80-
await init.app.request(url, { headers: headers }, env)
81+
const response = await init.app.request(url, { headers: headers }, env)
8182
const waiter = waiterMap.get(request)
8283

8384
if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
8485
socket.end(
85-
'HTTP/1.1 400 Bad Request\r\n' +
86+
`HTTP/1.1 ${response.status.toString()} ${STATUS_CODES[response.status] ?? ''}\r\n` +
8687
'Connection: close\r\n' +
8788
'Content-Length: 0\r\n' +
8889
'\r\n'

packages/ua-blocker/src/escape.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ function $escape(S: string): string {
6060
if (i === 0 && FIRST_DIGIT_OR_ASCII.exec(chr)) {
6161
result[i] = _escapeChar(chr)
6262
} else if (Object.prototype.hasOwnProperty.call(ControlEscape, chr)) {
63-
result[i] = '\\' + ControlEscape[chr]
63+
const escaped = ControlEscape[chr]
64+
if (escaped) {
65+
result[i] = '\\' + escaped
66+
}
6467
} else if (SYNTAX_SOLIDUS.exec(chr)) {
6568
result[i] = '\\' + chr
6669
} else if (OTHER_PUNCTUATORS_AND_WHITESPACES.exec(chr)) {

0 commit comments

Comments
 (0)