Skip to content

Commit

Permalink
Update for Fastify v5 (#347)
Browse files Browse the repository at this point in the history
* update

* remove coverage check

* update ci
  • Loading branch information
gurgunday authored Apr 27, 2024
1 parent 8a48934 commit bb9ddd3
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ on:

jobs:
test:
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v4.1.0
with:
license-check: true
7 changes: 2 additions & 5 deletions .taprc
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
ts: false
jsx: false
flow: false
coverage: true
check-coverage: true
files:
- test/**/*.js
31 changes: 15 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const kWsHead = Symbol('wsHead')
const kWsUpgradeListener = Symbol('wsUpgradeListener')

function liftErrorCode (code) {
/* istanbul ignore next */
/* c8 ignore start */
if (typeof code !== 'number') {
// Sometimes "close" event emits with a non-numeric value
return 1011
Expand All @@ -23,6 +23,7 @@ function liftErrorCode (code) {
} else {
return code
}
/* c8 ignore stop */
}

function closeWebSocket (socket, code, reason) {
Expand Down Expand Up @@ -52,27 +53,27 @@ function proxyWebSockets (source, target) {
}

source.on('message', (data, binary) => waitConnection(target, () => target.send(data, { binary })))
/* istanbul ignore next */
/* c8 ignore start */
source.on('ping', data => waitConnection(target, () => target.ping(data)))
/* istanbul ignore next */
source.on('pong', data => waitConnection(target, () => target.pong(data)))
/* c8 ignore stop */
source.on('close', close)
/* istanbul ignore next */
/* c8 ignore start */
source.on('error', error => close(1011, error.message))
/* istanbul ignore next */
source.on('unexpected-response', () => close(1011, 'unexpected response'))
/* c8 ignore stop */

// source WebSocket is already connected because it is created by ws server
target.on('message', (data, binary) => source.send(data, { binary }))
/* istanbul ignore next */
/* c8 ignore start */
target.on('ping', data => source.ping(data))
/* istanbul ignore next */
/* c8 ignore stop */
target.on('pong', data => source.pong(data))
target.on('close', close)
/* istanbul ignore next */
/* c8 ignore start */
target.on('error', error => close(1011, error.message))
/* istanbul ignore next */
target.on('unexpected-response', () => close(1011, 'unexpected response'))
/* c8 ignore stop */
}

function handleUpgrade (fastify, rawRequest, socket, head) {
Expand Down Expand Up @@ -129,7 +130,6 @@ class WebSocketProxy {
fastify.server.close = function (done) {
wss.close(() => {
oldClose.call(this, (err) => {
/* istanbul ignore next */
done && done(err)
})
})
Expand All @@ -139,11 +139,11 @@ class WebSocketProxy {
}
}

/* istanbul ignore next */
/* c8 ignore start */
wss.on('error', (err) => {
/* istanbul ignore next */
this.logger.error(err)
})
/* c8 ignore stop */

this.wss = wss
this.prefixList = []
Expand All @@ -167,7 +167,7 @@ class WebSocketProxy {

const upstream = this.getUpstream(request, '')
const target = new URL(dest, upstream)
/* istanbul ignore next */
/* c8 ignore next */
target.protocol = upstream.indexOf('http:') === 0 ? 'ws:' : 'wss'
target.search = search
return target
Expand Down Expand Up @@ -314,10 +314,9 @@ async function fastifyHttpProxy (fastify, opts) {
reply.hijack()
try {
wsProxy.handleUpgrade(request, dest || '/', noop)
} catch (err) {
/* istanbul ignore next */
} /* c8 ignore start */ catch (err) {
request.log.warn({ err }, 'websocket proxy error')
}
} /* c8 ignore stop */
return
}
reply.from(dest || '/', replyOpts)
Expand Down
36 changes: 18 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,34 @@
},
"homepage": "https://github.com/fastify/fastify-http-proxy#readme",
"devDependencies": {
"@fastify/pre-commit": "^2.0.2",
"@fastify/websocket": "^9.0.0",
"@types/node": "^20.1.0",
"@types/ws": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"express": "^4.17.2",
"@fastify/pre-commit": "^2.1.0",
"@fastify/websocket": "^10.0.1",
"@types/node": "^20.12.7",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^7.6.0",
"@typescript-eslint/parser": "^7.6.0",
"express": "^4.19.2",
"express-http-proxy": "^2.0.0",
"fast-proxy": "^2.1.0",
"fastify": "^4.0.0-rc.2",
"got": "^11.8.3",
"fastify": "^4.26.2",
"got": "^11.8.6",
"http-errors": "^2.0.0",
"http-proxy": "^1.18.1",
"simple-get": "^4.0.0",
"simple-get": "^4.0.1",
"snazzy": "^9.0.0",
"socket.io": "^4.4.1",
"socket.io-client": "^4.4.1",
"standard": "^17.0.0",
"tap": "^16.0.0",
"socket.io": "^4.7.5",
"socket.io-client": "^4.7.5",
"standard": "^17.1.0",
"tap": "^18.7.2",
"tsd": "^0.31.0",
"typescript": "^5.0.2",
"typescript": "^5.4.5",
"why-is-node-running": "^2.2.2"
},
"dependencies": {
"@fastify/reply-from": "^9.0.0",
"@fastify/reply-from": "^9.7.0",
"fast-querystring": "^1.1.2",
"fastify-plugin": "^4.5.0",
"ws": "^8.4.2"
"fastify-plugin": "^4.5.1",
"ws": "^8.16.0"
},
"tsd": {
"directory": "test/types"
Expand Down
75 changes: 75 additions & 0 deletions test/websocket-pathname.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const { test } = require('tap')
const Fastify = require('fastify')
const proxy = require('..')
const WebSocket = require('ws')
const { createServer } = require('node:http')
const { promisify } = require('node:util')
const { once } = require('node:events')

// TODO: this test is flaky, probably because of promise resolution
test('keep proxy websocket pathname', async (t) => {
t.plan(5)

const origin = createServer()
const wss = new WebSocket.Server({ server: origin })

t.teardown(wss.close.bind(wss))
t.teardown(origin.close.bind(origin))

const serverMessages = []
wss.on('connection', (ws, request) => {
ws.on('message', (message, binary) => {
// Also need save request.url for check from what url the message is coming.
serverMessages.push([message.toString(), binary, request.headers.host.split(':', 1)[0], request.url])
ws.send(message, { binary })
})
})

await promisify(origin.listen.bind(origin))({ port: 0, host: '127.0.0.1' })
// Host for wsUpstream and for later check.
const host = '127.0.0.1'
// Path for wsUpstream and for later check.
const path = '/keep/path'
const server = Fastify()
server.register(proxy, {
upstream: `ws://127.0.0.1:${origin.address().port}`,
// Start proxy with different upstream, without path
wsUpstream: `ws://${host}:${origin.address().port}`,
websocket: true
})

await server.listen({ port: 0, host: '127.0.0.1' })
t.teardown(server.close.bind(server))

// Start websocket with different upstream for connect, added path.
const ws = new WebSocket(`ws://${host}:${server.server.address().port}${path}`)
await once(ws, 'open')

const data = [{ message: 'hello', binary: false }, { message: 'fastify', binary: true, isBuffer: true }]
const dataLength = data.length
let dataIndex = 0

for (; dataIndex < dataLength; dataIndex++) {
const { message: msg, binary, isBuffer } = data[dataIndex]
const message = isBuffer
? Buffer.from(msg)
: msg

ws.send(message, { binary })

const [reply, binaryAnswer] = await once(ws, 'message')

t.equal(reply.toString(), msg)
t.equal(binaryAnswer, binary)
}
// Also check "path", must be the same.
t.strictSame(serverMessages, [
['hello', false, host, path],
['fastify', true, host, path]
])

await Promise.all([
once(ws, 'close'),
server.close()
])
})
67 changes: 0 additions & 67 deletions test/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,70 +574,3 @@ test('multiple websocket upstreams with distinct server options', async (t) => {
server.close()
])
})

test('keep proxy websocket pathname', async (t) => {
t.plan(5)

const origin = createServer()
const wss = new WebSocket.Server({ server: origin })

t.teardown(wss.close.bind(wss))
t.teardown(origin.close.bind(origin))

const serverMessages = []
wss.on('connection', (ws, request) => {
ws.on('message', (message, binary) => {
// Also need save request.url for check from what url the message is coming.
serverMessages.push([message.toString(), binary, request.headers.host.split(':', 1)[0], request.url])
ws.send(message, { binary })
})
})

await promisify(origin.listen.bind(origin))({ port: 0, host: '127.0.0.1' })
// Host for wsUpstream and for later check.
const host = '127.0.0.1'
// Path for wsUpstream and for later check.
const path = '/keep/path'
const server = Fastify()
server.register(proxy, {
upstream: `ws://127.0.0.1:${origin.address().port}`,
// Start proxy with different upstream, without path
wsUpstream: `ws://${host}:${origin.address().port}`,
websocket: true
})

await server.listen({ port: 0, host: '127.0.0.1' })
t.teardown(server.close.bind(server))

// Start websocket with different upstream for connect, added path.
const ws = new WebSocket(`ws://${host}:${server.server.address().port}${path}`)
await once(ws, 'open')

const data = [{ message: 'hello', binary: false }, { message: 'fastify', binary: true, isBuffer: true }]
const dataLength = data.length
let dataIndex = 0

for (; dataIndex < dataLength; dataIndex++) {
const { message: msg, binary, isBuffer } = data[dataIndex]
const message = isBuffer
? Buffer.from(msg)
: msg

ws.send(message, { binary })

const [reply, binaryAnswer] = await once(ws, 'message')

t.equal(reply.toString(), msg)
t.equal(binaryAnswer, binary)
}
// Also check "path", must be the same.
t.strictSame(serverMessages, [
['hello', false, host, path],
['fastify', true, host, path]
])

await Promise.all([
once(ws, 'close'),
server.close()
])
})
9 changes: 6 additions & 3 deletions test/ws-prefix-rewrite-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,12 @@ async function handleProxy (info, { backendPath, proxyOptions, wrapperOptions },
handler: (req, reply) => {
reply.send(req.url)
},
wsHandler: (conn, req) => {
conn.write(req.url)
conn.end()
wsHandler: (socket, req) => {
socket.send(req.url)

socket.once('message', chunk => {
socket.close()
})
}
})

Expand Down
9 changes: 6 additions & 3 deletions test/ws-prefix-rewrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ async function handleProxy (info, { backendPath, proxyOptions, wrapperOptions },
handler: (req, reply) => {
reply.send(req.url)
},
wsHandler: (conn, req) => {
conn.write(req.url)
conn.end()
wsHandler: (socket, req) => {
socket.send(req.url)

socket.once('message', chunk => {
socket.close()
})
}
})

Expand Down

0 comments on commit bb9ddd3

Please sign in to comment.