Socket
Socket
Sign inDemoInstall

http2-proxy

Package Overview
Dependencies
Maintainers
1
Versions
193
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

http2-proxy - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0-beta.1

153

index.js

@@ -21,2 +21,3 @@ const http2 = require('http2')

HTTP2_HEADER_VIA,
HTTP2_HEADER_STATUS,
// XXX https://github.com/nodejs/node/issues/15337

@@ -30,4 +31,4 @@ HTTP2_HEADER_FORWARDED = 'forwarded'

},
web (req, res, options, callback) {
proxy(req, res, null, options, callback)
web (reqOrStream, resOrHeaders, options, callback) {
proxy(reqOrStream, resOrHeaders, null, options, callback)
}

@@ -43,3 +44,10 @@ }

const kOnProxyRes = Symbol('onProxyRes')
const kFinished = Symbol('finished')
const RESPOND_OPTIONS = {
getTrailers: function () {
return this[kProxyRes].trailers
}
}
function proxy (req, res, head, {

@@ -54,4 +62,16 @@ hostname,

}, callback) {
req[kRes] = res
let reqHeaders = req.headers
let reqMethod = req.method
let reqUrl = req.url
if (!reqHeaders) {
reqHeaders = res
reqMethod = reqHeaders[HTTP2_HEADER_METHOD]
reqUrl = reqHeaders[HTTP2_HEADER_PATH]
res = req
} else {
req[kRes] = res
}
res[kReq] = req

@@ -63,2 +83,3 @@ res[kRes] = res

res[kProxySocket] = null
res[kFinished] = false

@@ -75,29 +96,19 @@ assert(typeof callback === 'function' || callback == null)

if (proxyName && reqHeaders[HTTP2_HEADER_VIA]) {
for (const name of reqHeaders[HTTP2_HEADER_VIA].split(',')) {
if (sanitize(name).endsWith(proxyName.toLowerCase())) {
return onFinish.call(res, createError('loop detected', null, 508))
}
}
}
if (res instanceof net.Socket) {
if (req.method !== 'GET') {
if (reqMethod !== 'GET') {
return onFinish.call(res, createError('method not allowed', null, 405))
}
if (sanitize(req.headers[HTTP2_HEADER_UPGRADE]) !== 'websocket') {
if (sanitize(reqHeaders[HTTP2_HEADER_UPGRADE]) !== 'websocket') {
return onFinish.call(res, createError('bad request', null, 400))
}
}
if (req.httpVersion !== '1.1' && req.httpVersion !== '2.0') {
return onFinish.call(res, createError('http version not supported', null, 505))
}
if (proxyName && req.headers[HTTP2_HEADER_VIA]) {
for (const name of req.headers[HTTP2_HEADER_VIA].split(',')) {
if (sanitize(name).endsWith(proxyName.toLowerCase())) {
return onFinish.call(res, createError('loop detected', null, 508))
}
}
}
if (timeout) {
req.setTimeout(timeout, onRequestTimeout)
}
if (res instanceof net.Socket) {
if (head && head.length) {

@@ -110,4 +121,8 @@ res.unshift(head)

const headers = getRequestHeaders(req)
if (timeout != null) {
req.setTimeout(timeout, onRequestTimeout)
}
const headers = getRequestHeaders(reqHeaders, req.socket)
if (proxyName) {

@@ -122,6 +137,6 @@ if (headers[HTTP2_HEADER_VIA]) {

const options = {
method: req.method,
method: reqMethod,
hostname,
port,
path: req.url,
path: reqUrl,
headers,

@@ -143,10 +158,17 @@ timeout: proxyTimeout

res
.on('finish', onFinish)
.on('close', onFinish)
.on('error', onFinish)
if (req instanceof http2.Http2Stream) {
req
.on('streamClosed', onFinish)
.on('finish', onFinish)
} else {
req
.on('close', onFinish)
res
.on('finish', onFinish)
.on('close', onFinish)
.on('error', onFinish)
}
req
.on('aborted', onFinish)
.on('close', onFinish)
.on('error', onFinish)

@@ -170,6 +192,8 @@ .pipe(proxyReq)

if (!res[kProxyCallback]) {
if (!res[kFinished]) {
return
}
res[kFinished] = true
if (err) {

@@ -191,3 +215,7 @@ err.statusCode = statusCode || err.statusCode || 500

} else {
res.writeHead(statusCode)
if (res.respond) {
res.respond({ [HTTP2_HEADER_STATUS]: statusCode })
} else {
res.writeHead(statusCode)
}
res.end()

@@ -197,3 +225,3 @@ }

if (res[kProxyCallback]) {
res[kProxyCallback].call(res[kProxyReq], err, res[kReq], res)
res[kProxyCallback].call(null, err, res[kReq], res)
res[kProxyCallback] = null

@@ -246,12 +274,23 @@ }

res.statusCode = proxyRes.statusCode
for (const key of Object.keys(proxyRes.headers)) {
res.setHeader(key, proxyRes.headers[key])
}
if (res.respond) {
proxyRes.headers[HTTP2_HEADER_STATUS] = proxyRes.status
if (this[kOnProxyRes]) {
this[kOnProxyRes](this[kReq], res)
if (this[kOnProxyRes]) {
this[kOnProxyRes](this[kReq], proxyRes.headers)
}
res.respond(proxyRes.headers, RESPOND_OPTIONS)
} else {
res.statusCode = proxyRes.statusCode
for (const key of Object.keys(proxyRes.headers)) {
res.setHeader(key, proxyRes.headers[key])
}
if (this[kOnProxyRes]) {
this[kOnProxyRes](this[kReq], res)
}
res.writeHead(res.statusCode)
}
res.writeHead(res.statusCode)
proxyRes

@@ -307,3 +346,3 @@ .on('end', onProxyTrailers)

this[kRes].write(head)
res.write(head)

@@ -315,20 +354,18 @@ proxyRes

.on('error', onFinish)
.pipe(this[kRes])
.pipe(res)
.pipe(proxySocket)
}
function getRequestHeaders (req) {
const host = req.headers[HTTP2_HEADER_AUTHORITY] || req.headers[HTTP2_HEADER_HOST]
const upgrade = req.headers[HTTP2_HEADER_UPGRADE]
const forwarded = req.headers[HTTP2_HEADER_FORWARDED]
function getRequestHeaders (req, reqHeaders, reqSocket) {
const host = reqHeaders[HTTP2_HEADER_AUTHORITY] || reqHeaders[HTTP2_HEADER_HOST]
const upgrade = reqHeaders[HTTP2_HEADER_UPGRADE]
const forwarded = reqHeaders[HTTP2_HEADER_FORWARDED]
const headers = setupHeaders(Object.assign({}, req.headers))
const headers = setupHeaders(Object.assign({}, reqHeaders))
if (req.httpVersionMajor === 2) {
// Remove pseudo headers
delete headers[HTTP2_HEADER_AUTHORITY]
delete headers[HTTP2_HEADER_METHOD]
delete headers[HTTP2_HEADER_PATH]
delete headers[HTTP2_HEADER_SCHEME]
}
// Remove pseudo headers
delete headers[HTTP2_HEADER_AUTHORITY]
delete headers[HTTP2_HEADER_METHOD]
delete headers[HTTP2_HEADER_PATH]
delete headers[HTTP2_HEADER_SCHEME]

@@ -340,4 +377,4 @@ if (upgrade) {

headers[HTTP2_HEADER_FORWARDED] = `by=${req.socket.localAddress}`
headers[HTTP2_HEADER_FORWARDED] += `; for=${req.socket.remoteAddress}`
headers[HTTP2_HEADER_FORWARDED] = `by=${reqSocket.localAddress}`
headers[HTTP2_HEADER_FORWARDED] += `; for=${reqSocket.remoteAddress}`

@@ -359,3 +396,3 @@ if (forwarded) {

headers[HTTP2_HEADER_FORWARDED] += `; proto=${req.socket.encrypted ? 'https' : 'http'}`
headers[HTTP2_HEADER_FORWARDED] += `; proto=${reqSocket.encrypted ? 'https' : 'http'}`

@@ -362,0 +399,0 @@ return headers

{
"name": "http2-proxy",
"version": "1.0.2",
"version": "1.1.0-beta.1",
"scripts": {

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

@@ -24,3 +24,3 @@ # node-http2-proxy

### Usage
### HTTP/1 API

@@ -37,3 +37,3 @@ You must pass `allowHTTP1: true` to the `http2.createServer` or `http2.createSecureServer` factory methods.

#### Proxy HTTP 1.1/2 and WebSocket
#### Proxy HTTP/2, HTTP/1.1 and WebSocket

@@ -79,3 +79,3 @@ ```js

#### Add x-forwarded headers
#### Add x-forwarded headers

@@ -100,4 +100,2 @@ ```javascript

### API
#### web (req, res, options, [callback])

@@ -140,4 +138,77 @@

### HTTP/2 API
If HTTP/1 support is not required use the HTTP/2 `stream` API which has a lower overhead.
```js
import http2 from 'http2'
import proxy from 'http2-proxy'
const server = http2.createServer()
server.listen(8000)
```
#### Proxy HTTP/2
```js
server.on('stream', (stream, headers) => {
proxy.web(stream, headers, {
hostname: 'localhost'
port: 9000
}, err => {
if (err) {
console.error('proxy error', err)
}
})
})
```
#### Add x-forwarded headers
```javascript
server.on('stream', (stream, headers) => {
proxy.web(stream, { headers }, {
hostname: 'localhost'
port: 9000,
onReq: (stream, headers) => {
headers['x-forwarded-for'] = stream.socket.remoteAddress
headers['x-forwarded-proto'] = stream.socket.encrypted ? 'https' : 'http'
headers['x-forwarded-host'] = stream.headers['host']
}
}, err => {
if (err) {
console.error('proxy error', err)
}
})
})
```
#### web (stream, headers, options, [callback])
- `stream`: [`http2.Http2Stream`](https://nodejs.org/api/http2.html#http2_class_http2_http2stream)
- `headers`: Request headers object
- `options`: See [Options](#options)
- `callback(err)`: Called on completion or error. Optional
Returns a promise if no callback is provided.
See [`request`](https://nodejs.org/api/http.html#http_event_request)
### Options
- `hostname`: Proxy [`http.request(options)`](https://nodejs.org/api/http.html#http_http_request_options_callback) target hostname
- `port`: Proxy [`http.request(options)`](https://nodejs.org/api/http.html#http_http_request_options_callback) target port
- `proxyTimeout`: Proxy [`http.request(options)`](https://nodejs.org/api/http.html#http_http_request_options_callback) timeout
- `proxyName`: Proxy name used for **Via** header
- `timeout`: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) or [`http2.Http2ServerRequest`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverrequest) timeout
- `onReq(req, options)`: Called before proxy request
- `req`: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) or [`http2.Http2ServerRequest`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverrequest)
- `options`: Options passed to [`http.request(options)`](https://nodejs.org/api/http.html#http_http_request_options_callback)
- `onRes(req, headers)`: Called before proxy response
- `req`: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) or [`http2.Http2ServerRequest`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverrequest)
- `headers`: Response headers object
### License
[MIT](LICENSE)
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