Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@fastify/http-proxy

Package Overview
Dependencies
Maintainers
19
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/http-proxy - npm Package Compare versions

Comparing version 8.1.0 to 8.2.0

116

index.js

@@ -61,33 +61,72 @@ 'use strict'

function setupWebSocketProxy (fastify, options, rewritePrefix) {
const server = new WebSocket.Server({
server: fastify.server,
...options.wsServerOptions
})
class WebSocketProxy {
constructor (fastify, wsServerOptions) {
this.logger = fastify.log
fastify.addHook('onClose', (instance, done) => server.close(done))
const wss = new WebSocket.Server({
server: fastify.server,
...wsServerOptions
})
// To be able to close the HTTP server,
// all WebSocket clients need to be disconnected.
// Fastify is missing a pre-close event, or the ability to
// add a hook before the server.close call. We need to resort
// to monkeypatching for now.
const oldClose = fastify.server.close
fastify.server.close = function (done) {
for (const client of server.clients) {
client.close()
// To be able to close the HTTP server,
// all WebSocket clients need to be disconnected.
// Fastify is missing a pre-close event, or the ability to
// add a hook before the server.close call. We need to resort
// to monkeypatching for now.
const oldClose = fastify.server.close
fastify.server.close = function (done) {
for (const client of wss.clients) {
client.close()
}
oldClose.call(this, done)
}
oldClose.call(this, done)
wss.on('error', (err) => {
this.logger.error(err)
})
wss.on('connection', this.handleConnection.bind(this))
this.wss = wss
this.prefixList = []
}
server.on('error', (err) => {
fastify.log.error(err)
})
close (done) {
this.wss.close(done)
}
server.on('connection', (source, request) => {
if (fastify.prefix && !request.url.startsWith(fastify.prefix)) {
fastify.log.debug({ url: request.url }, 'not matching prefix')
addUpstream (prefix, rewritePrefix, upstream, wsClientOptions) {
this.prefixList.push({
prefix: new URL(prefix, 'ws://127.0.0.1').pathname,
rewritePrefix,
upstream: convertUrlToWebSocket(upstream),
wsClientOptions
})
// sort by decreasing prefix length, so that findUpstreamUrl() does longest prefix match
this.prefixList.sort((a, b) => b.prefix.length - a.prefix.length)
}
findUpstream (request) {
const source = new URL(request.url, 'ws://127.0.0.1')
for (const { prefix, rewritePrefix, upstream, wsClientOptions } of this.prefixList) {
if (source.pathname.startsWith(prefix)) {
const target = new URL(source.pathname.replace(prefix, rewritePrefix), upstream)
target.search = source.search
return { target, wsClientOptions }
}
}
return undefined
}
handleConnection (source, request) {
const upstream = this.findUpstream(request)
if (!upstream) {
this.logger.debug({ url: request.url }, 'not matching prefix')
source.close()
return
}
const { target: url, wsClientOptions } = upstream

@@ -102,27 +141,28 @@ const subprotocols = []

const headers = { cookie: request.headers.cookie }
optionsWs = { ...options.wsClientOptions, headers }
optionsWs = { ...wsClientOptions, headers }
} else {
optionsWs = options.wsClientOptions
optionsWs = wsClientOptions
}
const url = createWebSocketUrl(request)
const target = new WebSocket(url, subprotocols, optionsWs)
fastify.log.debug({ url: url.href }, 'proxy websocket')
this.logger.debug({ url: url.href }, 'proxy websocket')
proxyWebSockets(source, target)
})
}
}
function createWebSocketUrl (request) {
const source = new URL(request.url, 'ws://127.0.0.1')
const httpWss = new WeakMap() // http.Server => WebSocketProxy
const target = new URL(
source.pathname.replace(fastify.prefix, rewritePrefix),
convertUrlToWebSocket(options.upstream)
)
function setupWebSocketProxy (fastify, options, rewritePrefix) {
let wsProxy = httpWss.get(fastify.server)
if (!wsProxy) {
wsProxy = new WebSocketProxy(fastify, options.wsServerOptions)
httpWss.set(fastify.server, wsProxy)
target.search = source.search
fastify.addHook('onClose', (instance, done) => {
httpWss.delete(fastify.server)
wsProxy.close(done)
})
}
return target
}
wsProxy.addUpstream(fastify.prefix, rewritePrefix, options.upstream, options.wsClientOptions)
}

@@ -129,0 +169,0 @@

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

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -163,2 +163,6 @@ # @fastify/http-proxy

[`@fastify/websocket`](https://github.com/fastify/fastify-websocket).
Multiple websocket proxies may be attached to the same HTTP server at different paths.
In this case, only the first `wsServerOptions` is applied.
A few things are missing:

@@ -165,0 +169,0 @@

@@ -60,2 +60,48 @@ 'use strict'

test('multiple websocket upstreams', async (t) => {
t.plan(8)
const server = Fastify()
for (const name of ['/A', '/A/B', '/C/D', '/C']) {
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 })
server.register(proxy, {
prefix: name,
upstream: `ws://localhost:${origin.address().port}`,
websocket: true
})
}
await server.listen({ port: 0 })
t.teardown(server.close.bind(server))
const wsClients = []
for (const name of ['/A', '/A/B', '/C/D', '/C']) {
const ws = new WebSocket(`ws://localhost:${server.server.address().port}${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('captures errors on start', async (t) => {

@@ -62,0 +108,0 @@ const app = Fastify()

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc