Socket
Socket
Sign inDemoInstall

http2-proxy

Package Overview
Dependencies
0
Maintainers
1
Versions
193
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.2.11 to 0.2.12

464

index.js

@@ -31,7 +31,7 @@ const http2 = require('http2')

module.exports = {
ws (req, socket, head, options, onProxyError) {
impl(req, socket, head, options, onProxyError)
ws (req, socket, head, options, callback) {
impl(req, socket, head, options, callback)
},
web (req, res, options, onProxyError) {
impl(req, res, null, options, onProxyError)
web (req, res, options, callback) {
impl(req, res, null, options, callback)
}

@@ -48,32 +48,10 @@ }

onRes
}, onProxyError) {
let hasError = false
}, callback) {
const errorHandler = ErrorHandler.create(req, resOrSocket, callback)
function onError (err, statusCode = (err && err.statusCode) || 500) {
if (hasError) {
return
}
resOrSocket.on('error', errorHandler)
hasError = true
const incoming = req.stream || req
incoming.on('error', errorHandler)
if (resOrSocket.closed === true ||
resOrSocket.headersSent !== false ||
!resOrSocket.writeHead
) {
resOrSocket.destroy()
} else {
resOrSocket.writeHead(statusCode)
resOrSocket.end()
}
if (onProxyError) {
onProxyError(err, req, resOrSocket)
} else {
throw err
}
}
(req.stream || req).on('error', onError)
resOrSocket.on('error', onError)
try {

@@ -95,13 +73,12 @@ if (resOrSocket instanceof net.Socket) {

if (proxyName &&
req.headers[HTTP2_HEADER_VIA] &&
req.headers[HTTP2_HEADER_VIA]
.split(',')
.some(name => sanitize(name).endsWith(proxyName.toLowerCase()))
) {
throw createError('loop detected', null, 508)
if (proxyName && req.headers[HTTP2_HEADER_VIA]) {
for (const name of req.headers[HTTP2_HEADER_VIA].split(',')) {
if (sanitize(name).endsWith(proxyName.toLowerCase())) {
throw createError('loop detected', null, 508)
}
}
}
if (timeout) {
req.setTimeout(timeout, () => onError(createError('request timeout', null, 408)))
req.setTimeout(timeout, errorHandler.requestTimeout)
}

@@ -140,128 +117,23 @@

return proxy(req, resOrSocket, options, onRes, onError)
return proxy(req, resOrSocket, options, onRes, errorHandler)
} catch (err) {
return onError(err)
return errorHandler(err)
}
}
function proxy (req, resOrSocket, options, onRes, onError) {
function proxy (req, resOrSocket, options, onRes, errorHandler) {
const proxyReq = http.request(options)
const proxyErrorHandler = ProxyErrorHandler.create(req, proxyReq, errorHandler)
let hasError = false
const abort = () => {
if (!proxyReq.aborted) {
proxyReq.abort()
}
}
const callback = err => {
if (hasError) {
return
}
hasError = true
req.removeListener('close', abort)
abort()
onError(err)
}
req.on('close', abort)
req
.pipe(proxyReq)
.on('error', err => {
if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
err.statusCode = 503
callback(err)
} else if (/HPE_INVALID/.test(err.code)) {
err.statusCode = 502
callback(err)
} else if (err.code === 'ECONNRESET') {
if (!proxyReq.aborted) {
err.statusCode = 502
callback(err)
}
} else {
callback(err)
}
})
// NOTE http.ClientRequest emits "socket hang up" error when aborted, i.e.
// there is no need to listen for proxyReq.on('aborted', ...).
.on('timeout', () => callback(createError('gateway timeout', null, 504)))
.on('response', proxyRes => {
try {
proxyRes.on('aborted', () => callback(createError('socket hang up', 'ECONNRESET', 502)))
.on('error', proxyErrorHandler)
// NOTE http.ClientRequest emits "socket hang up" error when aborted
// before having received a response, i.e. there is no need to listen for
// proxyReq.on('aborted', ...).
.on('timeout', proxyErrorHandler.gatewayTimeout)
.on('response', ProxyResponseHandler.create(req, resOrSocket, onRes, proxyErrorHandler))
if (resOrSocket instanceof net.Socket) {
if (onRes) {
onRes(req, resOrSocket)
}
if (!proxyRes.upgrade) {
resOrSocket.end()
}
} else {
setupHeaders(proxyRes.headers)
resOrSocket.statusCode = proxyRes.statusCode
for (const key of Object.keys(proxyRes.headers)) {
resOrSocket.setHeader(key, proxyRes.headers[key])
}
if (onRes) {
onRes(req, resOrSocket)
}
resOrSocket.writeHead(resOrSocket.statusCode)
proxyRes.on('end', () => {
resOrSocket.addTrailers(proxyRes.trailers)
})
proxyRes
.on('error', callback)
.pipe(resOrSocket)
}
} catch (err) {
callback(err)
}
})
if (resOrSocket instanceof net.Socket) {
proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
try {
setupSocket(proxySocket)
if (proxyHead && proxyHead.length) {
proxySocket.unshift(proxyHead)
}
resOrSocket.write(
Object
.keys(proxyRes.headers)
.reduce((head, key) => {
const value = proxyRes.headers[key]
if (!Array.isArray(value)) {
head.push(key + ': ' + value)
return head
}
for (let i = 0; i < value.length; i++) {
head.push(key + ': ' + value[i])
}
return head
}, ['HTTP/1.1 101 Switching Protocols'])
.join('\r\n') + '\r\n\r\n'
)
proxyRes.on('error', callback)
proxySocket
.on('error', callback)
.pipe(resOrSocket)
.pipe(proxySocket)
} catch (err) {
callback(err)
}
})
proxyReq.on('upgrade', ProxyUpgradeHandler.create(req, resOrSocket, proxyErrorHandler))
}

@@ -345,1 +217,283 @@ }

}
class ErrorHandler {
constructor () {
this.hasError = false
this.req = null
this.resOrSocket = null
this.callback = null
this._release = this._release.bind(this)
this._handle = this._handle.bind(this)
this._handle.requestTimeout = this._requestTimeout.bind(this)
}
_requestTimeout () {
this._handle(createError('request timeout', null, 408))
}
_handle (err, statusCode = err.statusCode || 500) {
if (this.hasError) {
return
}
this.hasError = true
if (this.resOrSocket.closed === true ||
this.resOrSocket.headersSent !== false ||
!this.resOrSocket.writeHead
) {
this.resOrSocket.destroy()
} else {
this.resOrSocket.writeHead(statusCode)
this.resOrSocket.end()
}
if (this.callback) {
this.callback(err, this.req, this.resOrSocket)
} else {
throw err
}
}
_release () {
this.hasError = false
this.req = null
this.resOrSocket = null
this.callback = null
ErrorHandler.pool.push(this)
}
static create (req, resOrSocket, callback) {
const handler = ErrorHandler.pool.pop() || new ErrorHandler()
handler.hasError = false
handler.req = req
handler.resOrSocket = resOrSocket
handler.callback = callback
handler.req.on('close', handler._release)
return handler._handle
}
}
ErrorHandler.pool = []
class ProxyErrorHandler {
constructor () {
this.hasError = null
this.req = null
this.proxyReq = null
this.errorHandler = null
this._release = this._release.bind(this)
this._handle = this._handle.bind(this)
this._handle.gatewayTimeout = this._gatewayTimeout.bind(this)
this._handle.socketHangup = this._socketHangup.bind(this)
}
_handle (err) {
if (this.hasError) {
return
}
this.hasError = true
if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
err.statusCode = 503
} else if (/HPE_INVALID/.test(err.code)) {
err.statusCode = 502
} else if (err.code === 'ECONNRESET') {
if (!this.proxyReq.aborted) {
err.statusCode = 502
} else {
return
}
}
this._abort()
this.errorHandler(err)
}
_gatewayTimeout () {
this._handle(createError('gateway timeout', null, 504))
}
_socketHangup () {
this._handle(createError('socket hang up', 'ECONNRESET', 502))
}
_abort () {
if (!this.proxyReq.aborted) {
this.proxyReq.abort()
}
}
_release () {
this._abort()
this.hasError = null
this.req = null
this.proxyReq = null
this.errorHandler = null
ProxyErrorHandler.pool.push(this)
}
static create (req, proxyReq, errorHandler) {
const handler = ProxyErrorHandler.pool.pop() || new ProxyErrorHandler()
handler.req = req
handler.proxyReq = proxyReq
handler.errorHandler = errorHandler
handler.req.on('close', handler._release)
return handler._handle
}
}
ProxyErrorHandler.pool = []
class ProxyResponseHandler {
constructor () {
this.req = null
this.resOrSocket = null
this.onRes = null
this.proxyErrorHandler = null
this.proxyRes = null
this._handle = this._handle.bind(this)
this._addTrailers = this._addTrailers.bind(this)
this._release = this._release.bind(this)
}
_addTrailers () {
this.resOrSocket.addTrailers(this.proxyRes.trailers)
}
_handle (proxyRes) {
this.proxyRes = proxyRes
try {
proxyRes.on('aborted', this.proxyErrorHandler.socketHangup)
if (this.resOrSocket instanceof net.Socket) {
if (this.onRes) {
this.onRes(this.req, this.resOrSocket)
}
if (!proxyRes.upgrade) {
this.resOrSocket.end()
}
} else {
setupHeaders(proxyRes.headers)
this.resOrSocket.statusCode = proxyRes.statusCode
for (const key of Object.keys(proxyRes.headers)) {
this.resOrSocket.setHeader(key, proxyRes.headers[key])
}
if (this.onRes) {
this.onRes(this.req, this.resOrSocket)
}
this.resOrSocket.writeHead(this.resOrSocket.statusCode)
proxyRes.on('end', this._addTrailers)
proxyRes
.on('error', this.proxyErrorHandler)
.pipe(this.resOrSocket)
}
} catch (err) {
this.proxyErrorHandler(err)
}
}
_release () {
this.req = null
this.resOrSocket = null
this.onRes = null
this.proxyErrorHandler = null
this.proxyRes = null
ProxyResponseHandler.pool.push(this)
}
static create (req, resOrSocket, onRes, proxyErrorHandler) {
const handler = ProxyResponseHandler.pool.pop() || new ProxyResponseHandler()
handler.req = req
handler.resOrSocket = resOrSocket
handler.onRes = onRes
handler.proxyErrorHandler = proxyErrorHandler
handler.proxyRes = null
handler.req.on('close', handler._release)
return handler._handle
}
}
ProxyResponseHandler.pool = []
class ProxyUpgradeHandler {
constructor () {
this.req = null
this.resOrSocket = null
this.proxyErrorHandler = null
this.proxyRes = null
this.proxySocket = null
this._release = this._release.bind(this)
this._handle = this._handle.bind(this)
}
_handle (proxyRes, proxySocket, proxyHead) {
this.proxyRes = proxyRes
this.proxySocket = proxySocket
try {
setupSocket(proxySocket)
if (proxyHead && proxyHead.length) {
proxySocket.unshift(proxyHead)
}
let head = 'HTTP/1.1 101 Switching Protocols'
for (const key of Object.keys(proxyRes.headers)) {
const value = proxyRes.headers[key]
if (!Array.isArray(value)) {
head += '\r\n' + key + ': ' + value
} else {
for (let i = 0; i < value.length; i++) {
head += '\r\n' + key + ': ' + value[i]
}
}
}
head += '\r\n\r\n'
this.resOrSocket.write(head)
proxyRes.on('error', this.proxyErrorHandler)
proxySocket
.on('error', this.proxyErrorHandler)
.pipe(this.resOrSocket)
.pipe(proxySocket)
} catch (err) {
this.proxyErrorHandler(err)
}
}
_release () {
this.proxyRes.destroy()
this.proxySocket.destroy()
this.req = null
this.resOrSocket = null
this.proxyErrorHandler = null
this.proxyRes = null
this.proxySocket = null
ProxyUpgradeHandler.pool.push(this)
}
static create (req, resOrSocket, proxyErrorHandler) {
const handler = ProxyUpgradeHandler.pool.pop() || new ProxyUpgradeHandler()
handler.req = req
handler.resOrSocket = resOrSocket
handler.proxyErrorHandler = proxyErrorHandler
handler.req.on('close', handler._release)
return handler._handle
}
}
ProxyUpgradeHandler.pool = []
{
"name": "http2-proxy",
"version": "0.2.11",
"version": "0.2.12",
"scripts": {

@@ -5,0 +5,0 @@ "dev": "nodemon --inspect=9308 --expose-http2 src",

# node-http2-proxy
A simple http/2 & http/1.1 to http/1.1 spec compliant proxy helper for Node.
A simple high performance http/2 & http/1.1 to http/1.1 spec compliant proxy helper for Node.

@@ -9,2 +9,3 @@ ### Features

- Simple and easy to follow implementation
- GC friendly with minimal allocations
- [Hop by hop header handling](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)

@@ -11,0 +12,0 @@ - [Connection header handling](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection)

SocketSocket SOC 2 Logo

Product

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

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc