Socket
Socket
Sign inDemoInstall

@fastify/http-proxy

Package Overview
Dependencies
16
Maintainers
20
Versions
20
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 9.3.0 to 9.4.0

2

examples/example.js

@@ -14,3 +14,3 @@ 'use strict'

origin.get('/redirect', async (request, reply) => {
return reply.redirect(302, 'https://fastify.io')
return reply.redirect(302, 'https://fastify.dev')
})

@@ -17,0 +17,0 @@

@@ -13,2 +13,3 @@ 'use strict'

const kWsHead = Symbol('wsHead')
const kWsUpgradeListener = Symbol('wsUpgradeListener')

@@ -78,5 +79,27 @@ function liftErrorCode (code) {

function handleUpgrade (fastify, rawRequest, socket, head) {
// Save a reference to the socket and then dispatch the request through the normal fastify router so that it will invoke hooks and then eventually a route handler that might upgrade the socket.
rawRequest[kWs] = socket
rawRequest[kWsHead] = head
const rawResponse = new ServerResponse(rawRequest)
rawResponse.assignSocket(socket)
fastify.routing(rawRequest, rawResponse)
rawResponse.on('finish', () => {
socket.destroy()
})
}
class WebSocketProxy {
constructor (fastify, wsServerOptions) {
constructor (fastify, { wsServerOptions, wsClientOptions, upstream, wsUpstream, replyOptions: { getUpstream } = {} }) {
this.logger = fastify.log
this.wsClientOptions = {
rewriteRequestHeaders: defaultWsHeadersRewrite,
headers: {},
...wsClientOptions
}
this.upstream = convertUrlToWebSocket(upstream)
this.wsUpstream = wsUpstream ? convertUrlToWebSocket(wsUpstream) : ''
this.getUpstream = getUpstream

@@ -88,19 +111,11 @@ const wss = new WebSocket.Server({

fastify.server.on('upgrade', (rawRequest, socket, head) => {
// Save a reference to the socket and then dispatch the request through the normal fastify router so that it will invoke hooks and then eventually a route handler that might upgrade the socket.
rawRequest[kWs] = socket
rawRequest[kWsHead] = head
if (!fastify.server[kWsUpgradeListener]) {
fastify.server[kWsUpgradeListener] = (rawRequest, socket, head) =>
handleUpgrade(fastify, rawRequest, socket, head)
fastify.server.on('upgrade', fastify.server[kWsUpgradeListener])
}
const rawResponse = new ServerResponse(rawRequest)
rawResponse.assignSocket(socket)
fastify.routing(rawRequest, rawResponse)
rawResponse.on('finish', () => {
socket.destroy()
})
})
this.handleUpgrade = (request, cb) => {
this.handleUpgrade = (request, dest, cb) => {
wss.handleUpgrade(request.raw, request.raw[kWs], request.raw[kWsHead], (socket) => {
this.handleConnection(socket, request)
this.handleConnection(socket, request, dest)
cb()

@@ -140,41 +155,29 @@ })

addUpstream (prefix, rewritePrefix, upstream, wsUpstream, wsClientOptions) {
this.prefixList.push({
prefix: new URL(prefix, 'ws://127.0.0.1').pathname,
rewritePrefix,
upstream: convertUrlToWebSocket(upstream),
wsUpstream: wsUpstream ? convertUrlToWebSocket(wsUpstream) : '',
wsClientOptions
})
findUpstream (request, dest) {
const search = new URL(request.url, 'ws://127.0.0.1').search
// sort by decreasing prefix length, so that findUpstreamUrl() does longest prefix match
this.prefixList.sort((a, b) => b.prefix.length - a.prefix.length)
}
if (typeof this.wsUpstream === 'string' && this.wsUpstream !== '') {
const target = new URL(this.wsUpstream)
target.search = search
return target
}
findUpstream (request) {
const source = new URL(request.url, 'ws://127.0.0.1')
for (const { prefix, rewritePrefix, upstream, wsUpstream, wsClientOptions } of this.prefixList) {
if (wsUpstream) {
const target = new URL(wsUpstream)
target.search = source.search
return { target, wsClientOptions }
}
if (source.pathname.startsWith(prefix)) {
const target = new URL(source.pathname.replace(prefix, rewritePrefix), upstream)
target.search = source.search
return { target, wsClientOptions }
}
if (typeof this.upstream === 'string' && this.upstream !== '') {
const target = new URL(dest, this.upstream)
target.search = search
return target
}
const upstream = this.getUpstream(request, '')
const target = new URL(dest, upstream)
/* istanbul ignore next */
throw new Error(`no upstream found for ${request.url}. this should not happened. Please report to https://github.com/fastify/fastify-http-proxy`)
target.protocol = upstream.indexOf('http:') === 0 ? 'ws:' : 'wss'
target.search = search
return target
}
handleConnection (source, request) {
const upstream = this.findUpstream(request)
const { target: url, wsClientOptions } = upstream
const rewriteRequestHeaders = wsClientOptions?.rewriteRequestHeaders || defaultWsHeadersRewrite
const headersToRewrite = wsClientOptions?.headers || {}
handleConnection (source, request, dest) {
const url = this.findUpstream(request, dest)
const rewriteRequestHeaders = this.wsClientOptions.rewriteRequestHeaders
const headersToRewrite = this.wsClientOptions.headers

@@ -187,3 +190,3 @@ const subprotocols = []

const headers = rewriteRequestHeaders(headersToRewrite, request)
const optionsWs = { ...(wsClientOptions || {}), headers }
const optionsWs = { ...this.wsClientOptions, headers }

@@ -203,37 +206,2 @@ const target = new WebSocket(url, subprotocols, optionsWs)

const httpWss = new WeakMap() // http.Server => WebSocketProxy
function setupWebSocketProxy (fastify, options, rewritePrefix) {
let wsProxy = httpWss.get(fastify.server)
if (!wsProxy) {
wsProxy = new WebSocketProxy(fastify, options.wsServerOptions)
httpWss.set(fastify.server, wsProxy)
}
if (
(typeof options.wsUpstream === 'string' && options.wsUpstream !== '') ||
(typeof options.upstream === 'string' && options.upstream !== '')
) {
wsProxy.addUpstream(
fastify.prefix,
rewritePrefix,
options.upstream,
options.wsUpstream,
options.wsClientOptions
)
// The else block is validate earlier in the code
} else {
wsProxy.findUpstream = function (request) {
const source = new URL(request.url, 'ws://127.0.0.1')
const upstream = options.replyOptions.getUpstream(request, '')
const target = new URL(source.pathname, upstream)
/* istanbul ignore next */
target.protocol = upstream.indexOf('http:') === 0 ? 'ws:' : 'wss'
target.search = source.search
return { target, wsClientOptions: options.wsClientOptions }
}
}
return wsProxy
}
function generateRewritePrefix (prefix, opts) {

@@ -312,3 +280,3 @@ let rewritePrefix = opts.rewritePrefix || (opts.upstream ? new URL(opts.upstream).pathname : '/')

if (opts.websocket) {
wsProxy = setupWebSocketProxy(fastify, opts, rewritePrefix)
wsProxy = new WebSocketProxy(fastify, opts)
}

@@ -331,12 +299,2 @@

function handler (request, reply) {
if (request.raw[kWs]) {
reply.hijack()
try {
wsProxy.handleUpgrade(request, noop)
} catch (err) {
/* istanbul ignore next */
request.log.warn({ err }, 'websocket proxy error')
}
return
}
const { path, queryParams } = extractUrlComponents(request.url)

@@ -361,2 +319,13 @@ let dest = path

}
if (request.raw[kWs]) {
reply.hijack()
try {
wsProxy.handleUpgrade(request, dest || '/', noop)
} catch (err) {
/* istanbul ignore next */
request.log.warn({ err }, 'websocket proxy error')
}
return
}
reply.from(dest || '/', replyOpts)

@@ -363,0 +332,0 @@ }

{
"name": "@fastify/http-proxy",
"version": "9.3.0",
"version": "9.4.0",
"description": "proxy http requests, for Fastify",

@@ -51,3 +51,3 @@ "main": "index.js",

"tap": "^16.0.0",
"tsd": "^0.29.0",
"tsd": "^0.30.0",
"typescript": "^5.0.2",

@@ -54,0 +54,0 @@ "why-is-node-running": "^2.2.2"

@@ -8,3 +8,3 @@ # @fastify/http-proxy

Proxy your HTTP requests to another server, with hooks.
This [`fastify`](https://www.fastify.io) plugin forwards all requests
This [`fastify`](https://fastify.dev) plugin forwards all requests
received with a given prefix (or none) to an upstream. All Fastify hooks are still applied.

@@ -167,3 +167,3 @@

if (request.body.method === 'invalid_method') {
reply.code(400).send({ message: 'payload contains invalid method' });
return reply.code(400).send({ message: 'payload contains invalid method' });
}

@@ -177,3 +177,3 @@ },

An object accessible within the `preHandler` via `reply.context.config`.
See [Config](https://www.fastify.io/docs/v4.8.x/Reference/Routes/#config) in the Fastify
See [Config](https://fastify.dev/docs/v4.8.x/Reference/Routes/#config) in the Fastify
documentation for information on this option. Note: this is merged with other

@@ -225,5 +225,2 @@ configuration passed to the route.

In case multiple websocket proxies are attached to the same HTTP server at different paths.
In this case, only the first `wsServerOptions` is applied.
### `wsClientOptions`

@@ -230,0 +227,0 @@

@@ -22,3 +22,3 @@ 'use strict'

origin.get('/redirect', async (request, reply) => {
return reply.redirect(302, 'https://fastify.io')
return reply.redirect(302, 'https://fastify.dev')
})

@@ -125,3 +125,3 @@

)
t.equal(location, 'https://fastify.io')
t.equal(location, 'https://fastify.dev')
t.equal(statusCode, 302)

@@ -152,3 +152,3 @@ })

)
t.equal(location, 'https://fastify.io')
t.equal(location, 'https://fastify.dev')
t.equal(statusCode, 302)

@@ -155,0 +155,0 @@ })

@@ -477,1 +477,101 @@ 'use strict'

})
test('multiple websocket upstreams with host constraints', async (t) => {
t.plan(4)
const server = Fastify()
for (const name of ['foo', 'bar']) {
const origin = createServer()
const wss = new WebSocket.Server({ server: origin })
t.teardown(wss.close.bind(wss))
t.teardown(origin.close.bind(origin))
wss.once('connection', (ws) => {
ws.once('message', message => {
t.equal(message.toString(), `hello ${name}`)
// echo
ws.send(message)
})
})
await promisify(origin.listen.bind(origin))({ port: 0, host: '127.0.0.1' })
server.register(proxy, {
upstream: `ws://127.0.0.1:${origin.address().port}`,
websocket: true,
constraints: { host: name }
})
}
await server.listen({ port: 0, host: '127.0.0.1' })
t.teardown(server.close.bind(server))
const wsClients = []
for (const name of ['foo', 'bar']) {
const ws = new WebSocket(`ws://127.0.0.1:${server.server.address().port}`, { headers: { host: name } })
await once(ws, 'open')
ws.send(`hello ${name}`)
const [reply] = await once(ws, 'message')
t.equal(reply.toString(), `hello ${name}`)
wsClients.push(ws)
}
await Promise.all([
...wsClients.map(ws => once(ws, 'close')),
server.close()
])
})
test('multiple websocket upstreams with distinct server options', async (t) => {
t.plan(4)
const server = Fastify()
for (const name of ['foo', 'bar']) {
const origin = createServer()
const wss = new WebSocket.Server({ server: origin })
t.teardown(wss.close.bind(wss))
t.teardown(origin.close.bind(origin))
wss.once('connection', (ws, req) => {
t.equal(req.url, `/?q=${name}`)
ws.once('message', message => {
// echo
ws.send(message)
})
})
await promisify(origin.listen.bind(origin))({ port: 0, host: '127.0.0.1' })
server.register(proxy, {
upstream: `ws://127.0.0.1:${origin.address().port}`,
websocket: true,
constraints: { host: name },
wsServerOptions: {
verifyClient: ({ req }) => {
t.equal(req.url, `/?q=${name}`)
return true
}
}
})
}
await server.listen({ port: 0, host: '127.0.0.1' })
t.teardown(server.close.bind(server))
const wsClients = []
for (const name of ['foo', 'bar']) {
const ws = new WebSocket(
`ws://127.0.0.1:${server.server.address().port}/?q=${name}`,
{ headers: { host: name } }
)
await once(ws, 'open')
ws.send(`hello ${name}`)
await once(ws, 'message')
wsClients.push(ws)
}
await Promise.all([
...wsClients.map(ws => once(ws, 'close')),
server.close()
])
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc