Skip to content

Commit 37c939e

Browse files
authored
websocket pass through path (#341)
1 parent 45c162b commit 37c939e

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,12 @@ class WebSocketProxy {
150150
}
151151

152152
findUpstream (request, dest) {
153-
const search = new URL(request.url, 'ws://127.0.0.1').search
153+
const { search, pathname } = new URL(request.url, 'ws://127.0.0.1')
154154

155155
if (typeof this.wsUpstream === 'string' && this.wsUpstream !== '') {
156156
const target = new URL(this.wsUpstream)
157157
target.search = search
158+
target.pathname = target.pathname === '/' ? pathname : target.pathname
158159
return target
159160
}
160161

test/websocket.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,70 @@ test('multiple websocket upstreams with distinct server options', async (t) => {
574574
server.close()
575575
])
576576
})
577+
578+
test('keep proxy websocket pathname', async (t) => {
579+
t.plan(5)
580+
581+
const origin = createServer()
582+
const wss = new WebSocket.Server({ server: origin })
583+
584+
t.teardown(wss.close.bind(wss))
585+
t.teardown(origin.close.bind(origin))
586+
587+
const serverMessages = []
588+
wss.on('connection', (ws, request) => {
589+
ws.on('message', (message, binary) => {
590+
// Also need save request.url for check from what url the message is coming.
591+
serverMessages.push([message.toString(), binary, request.headers.host.split(':', 1)[0], request.url])
592+
ws.send(message, { binary })
593+
})
594+
})
595+
596+
await promisify(origin.listen.bind(origin))({ port: 0, host: '127.0.0.1' })
597+
// Host for wsUpstream and for later check.
598+
const host = '127.0.0.1'
599+
// Path for wsUpstream and for later check.
600+
const path = '/keep/path'
601+
const server = Fastify()
602+
server.register(proxy, {
603+
upstream: `ws://127.0.0.1:${origin.address().port}`,
604+
// Start proxy with different upstream, without path
605+
wsUpstream: `ws://${host}:${origin.address().port}`,
606+
websocket: true
607+
})
608+
609+
await server.listen({ port: 0, host: '127.0.0.1' })
610+
t.teardown(server.close.bind(server))
611+
612+
// Start websocket with different upstream for connect, added path.
613+
const ws = new WebSocket(`ws://${host}:${server.server.address().port}${path}`)
614+
await once(ws, 'open')
615+
616+
const data = [{ message: 'hello', binary: false }, { message: 'fastify', binary: true, isBuffer: true }]
617+
const dataLength = data.length
618+
let dataIndex = 0
619+
620+
for (; dataIndex < dataLength; dataIndex++) {
621+
const { message: msg, binary, isBuffer } = data[dataIndex]
622+
const message = isBuffer
623+
? Buffer.from(msg)
624+
: msg
625+
626+
ws.send(message, { binary })
627+
628+
const [reply, binaryAnswer] = await once(ws, 'message')
629+
630+
t.equal(reply.toString(), msg)
631+
t.equal(binaryAnswer, binary)
632+
}
633+
// Also check "path", must be the same.
634+
t.strictSame(serverMessages, [
635+
['hello', false, host, path],
636+
['fastify', true, host, path]
637+
])
638+
639+
await Promise.all([
640+
once(ws, 'close'),
641+
server.close()
642+
])
643+
})

0 commit comments

Comments
 (0)