http2-proxy
Advanced tools
Comparing version 0.2.12 to 0.2.13
220
index.js
@@ -25,2 +25,3 @@ const http2 = require('http2') | ||
const NODE_VER = process.version.match(/v(\d+).(\d+).(\d+)(?:-(.*))/).slice(1) | ||
const REQ_OPTIONS = {} | ||
@@ -56,69 +57,64 @@ if (NODE_VER[0] < 9 && (NODE_VER[0] !== 8 || NODE_VER[1] > 4)) { | ||
try { | ||
if (resOrSocket instanceof net.Socket) { | ||
if (req.method !== 'GET') { | ||
throw createError('method not allowed', null, 405) | ||
} | ||
if (!req.headers[HTTP2_HEADER_UPGRADE] || | ||
req.headers[HTTP2_HEADER_UPGRADE].toLowerCase() !== 'websocket') { | ||
throw createError('bad request', null, 400) | ||
} | ||
if (resOrSocket instanceof net.Socket) { | ||
if (req.method !== 'GET') { | ||
return errorHandler(createError('method not allowed', null, 405)) | ||
} | ||
if (!/1\.1|2\.\d/.test(req.httpVersion)) { | ||
throw createError('http version not supported', null, 505) | ||
if (!req.headers[HTTP2_HEADER_UPGRADE] || | ||
req.headers[HTTP2_HEADER_UPGRADE].toLowerCase() !== 'websocket') { | ||
return errorHandler(createError('bad request', null, 400)) | ||
} | ||
} | ||
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 (req.httpVersion !== '1.1' && req.httpVersion !== '2.0') { | ||
return errorHandler(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 errorHandler(createError('loop detected', null, 508)) | ||
} | ||
} | ||
} | ||
if (timeout) { | ||
req.setTimeout(timeout, errorHandler.requestTimeout) | ||
} | ||
if (timeout) { | ||
req.setTimeout(timeout, errorHandler.requestTimeout) | ||
} | ||
if (resOrSocket instanceof net.Socket) { | ||
if (headOrNil && headOrNil.length) { | ||
resOrSocket.unshift(headOrNil) | ||
} | ||
setupSocket(resOrSocket) | ||
if (resOrSocket instanceof net.Socket) { | ||
if (headOrNil && headOrNil.length) { | ||
resOrSocket.unshift(headOrNil) | ||
} | ||
const headers = getRequestHeaders(req) | ||
setupSocket(resOrSocket) | ||
} | ||
if (proxyName) { | ||
if (headers[HTTP2_HEADER_VIA]) { | ||
headers[HTTP2_HEADER_VIA] += `,${proxyName}` | ||
} else { | ||
headers[HTTP2_HEADER_VIA] = proxyName | ||
} | ||
} | ||
const headers = getRequestHeaders(req) | ||
const options = { | ||
method: req.method, | ||
hostname, | ||
port, | ||
path: req.url, | ||
headers, | ||
timeout: proxyTimeout | ||
if (proxyName) { | ||
if (headers[HTTP2_HEADER_VIA]) { | ||
headers[HTTP2_HEADER_VIA] += `,${proxyName}` | ||
} else { | ||
headers[HTTP2_HEADER_VIA] = proxyName | ||
} | ||
} | ||
if (onReq) { | ||
onReq(req, options) | ||
} | ||
REQ_OPTIONS.method = req.method | ||
REQ_OPTIONS.hostname = hostname | ||
REQ_OPTIONS.port = port | ||
REQ_OPTIONS.path = req.url | ||
REQ_OPTIONS.headers = headers | ||
REQ_OPTIONS.timeout = proxyTimeout | ||
return proxy(req, resOrSocket, options, onRes, errorHandler) | ||
} catch (err) { | ||
return errorHandler(err) | ||
if (onReq) { | ||
onReq(req, REQ_OPTIONS) | ||
} | ||
const proxyReq = http.request(REQ_OPTIONS) | ||
proxy(req, resOrSocket, proxyReq, onRes, errorHandler) | ||
} | ||
function proxy (req, resOrSocket, options, onRes, errorHandler) { | ||
const proxyReq = http.request(options) | ||
function proxy (req, resOrSocket, proxyReq, onRes, errorHandler) { | ||
const proxyErrorHandler = ProxyErrorHandler.create(req, proxyReq, errorHandler) | ||
@@ -141,2 +137,6 @@ | ||
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] | ||
const headers = setupHeaders(Object.assign({}, req.headers)) | ||
@@ -150,3 +150,3 @@ | ||
if (req.headers[HTTP2_HEADER_UPGRADE]) { | ||
if (upgrade) { | ||
headers[HTTP2_HEADER_CONNECTION] = 'upgrade' | ||
@@ -159,6 +159,6 @@ headers[HTTP2_HEADER_UPGRADE] = 'websocket' | ||
if (req.headers[HTTP2_HEADER_FORWARDED]) { | ||
if (forwarded) { | ||
const expr = /for=\s*([^\s]+)/ig | ||
while (true) { | ||
const m = expr.exec(req.headers[HTTP2_HEADER_FORWARDED]) | ||
const m = expr.exec(forwarded) | ||
if (!m) { | ||
@@ -171,3 +171,2 @@ break | ||
const host = req.headers[HTTP2_HEADER_AUTHORITY] || req.headers[HTTP2_HEADER_HOST] | ||
if (host) { | ||
@@ -265,2 +264,3 @@ headers[HTTP2_HEADER_FORWARDED] += `; host=${host}` | ||
this.callback = null | ||
ErrorHandler.pool.push(this) | ||
@@ -283,6 +283,7 @@ } | ||
constructor () { | ||
this.hasError = null | ||
this.hasError = false | ||
this.req = null | ||
this.proxyReq = null | ||
this.errorHandler = null | ||
this.hpeExpr = /HPE_INVALID/ | ||
@@ -304,3 +305,3 @@ this._release = this._release.bind(this) | ||
err.statusCode = 503 | ||
} else if (/HPE_INVALID/.test(err.code)) { | ||
} else if (this.hpeExpr.test(err.code)) { | ||
err.statusCode = 502 | ||
@@ -336,6 +337,7 @@ } else if (err.code === 'ECONNRESET') { | ||
this.hasError = null | ||
this.hasError = false | ||
this.req = null | ||
this.proxyReq = null | ||
this.errorHandler = null | ||
ProxyErrorHandler.pool.push(this) | ||
@@ -375,33 +377,29 @@ } | ||
try { | ||
proxyRes.on('aborted', this.proxyErrorHandler.socketHangup) | ||
proxyRes.on('aborted', this.proxyErrorHandler.socketHangup) | ||
if (this.resOrSocket instanceof net.Socket) { | ||
if (this.onRes) { | ||
this.onRes(this.req, this.resOrSocket) | ||
} | ||
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) | ||
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]) | ||
} | ||
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) | ||
} | ||
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) | ||
this.resOrSocket.writeHead(this.resOrSocket.statusCode) | ||
proxyRes.on('end', this._addTrailers) | ||
proxyRes | ||
.on('error', this.proxyErrorHandler) | ||
.pipe(this.resOrSocket) | ||
} | ||
@@ -411,2 +409,6 @@ } | ||
_release () { | ||
if (this.proxyRes) { | ||
this.proxyRes.destroy() | ||
} | ||
this.req = null | ||
@@ -417,2 +419,3 @@ this.resOrSocket = null | ||
this.proxyRes = null | ||
ProxyResponseHandler.pool.push(this) | ||
@@ -450,41 +453,41 @@ } | ||
try { | ||
setupSocket(proxySocket) | ||
setupSocket(proxySocket) | ||
if (proxyHead && proxyHead.length) { | ||
proxySocket.unshift(proxyHead) | ||
} | ||
if (proxyHead && proxyHead.length) { | ||
proxySocket.unshift(proxyHead) | ||
} | ||
let head = 'HTTP/1.1 101 Switching Protocols' | ||
let head = 'HTTP/1.1 101 Switching Protocols' | ||
for (const key of Object.keys(proxyRes.headers)) { | ||
const value = proxyRes.headers[key] | ||
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] | ||
} | ||
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' | ||
head += '\r\n\r\n' | ||
this.resOrSocket.write(head) | ||
this.resOrSocket.write(head) | ||
proxyRes.on('error', this.proxyErrorHandler) | ||
proxyRes.on('error', this.proxyErrorHandler) | ||
proxySocket | ||
.on('error', this.proxyErrorHandler) | ||
.pipe(this.resOrSocket) | ||
.pipe(proxySocket) | ||
} catch (err) { | ||
this.proxyErrorHandler(err) | ||
} | ||
proxySocket | ||
.on('error', this.proxyErrorHandler) | ||
.pipe(this.resOrSocket) | ||
.pipe(proxySocket) | ||
} | ||
_release () { | ||
this.proxyRes.destroy() | ||
this.proxySocket.destroy() | ||
if (this.proxyRes) { | ||
this.proxyRes.destroy() | ||
} | ||
if (this.proxySocket) { | ||
this.proxySocket.destroy() | ||
} | ||
@@ -496,2 +499,3 @@ this.req = null | ||
this.proxySocket = null | ||
ProxyUpgradeHandler.pool.push(this) | ||
@@ -498,0 +502,0 @@ } |
{ | ||
"name": "http2-proxy", | ||
"version": "0.2.12", | ||
"version": "0.2.13", | ||
"scripts": { | ||
@@ -5,0 +5,0 @@ "dev": "nodemon --inspect=9308 --expose-http2 src", |
@@ -23,3 +23,3 @@ # node-http2-proxy | ||
`http2-proxy` requires node **v8.5.0** or newer with `http2` enabled. See [nightly node builds](https://nodejs.org/download/nightly/) or [building node from source](https://github.com/nodejs/node/blob/master/BUILDING.md#building-nodejs-on-supported-platforms). Pass the `--expose-http2` option when starting node **v8.x.x**. | ||
`http2-proxy` requires node **v8.5.0** or newer with `http2` enabled. Pass the `--expose-http2` option when starting node **v8.x.x**. | ||
@@ -87,6 +87,6 @@ ### Usage | ||
- `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) | ||
- `res`: [`http.ServerResponse`](https://nodejs.org/api/http.html#http_http_request_options_callback) or [`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverresponse) | ||
- `options`: see [Options](#options) | ||
- `onProxyError(err)`: called on error | ||
- `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). | ||
- `res`: [`http.ServerResponse`](https://nodejs.org/api/http.html#http_http_request_options_callback) or [`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverresponse). | ||
- `options`: See [Options](#options). | ||
- `onProxyError(err)`: Called on error. | ||
@@ -97,7 +97,7 @@ See [`request`](https://nodejs.org/api/http.html#http_event_request) | ||
- `req`: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) | ||
- `socket`: [`net.Socket`](https://nodejs.org/api/net.html#net_class_net_socket) | ||
- `head`: [`Buffer`](https://nodejs.org/api/buffer.html#buffer_class_buffer) | ||
- `options`: see [Options](#options) | ||
- `onProxyError(err)`: called on error | ||
- `req`: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage). | ||
- `socket`: [`net.Socket`](https://nodejs.org/api/net.html#net_class_net_socket). | ||
- `head`: [`Buffer`](https://nodejs.org/api/buffer.html#buffer_class_buffer). | ||
- `options`: See [Options](#options). | ||
- `onProxyError(err)`: Called on error. | ||
@@ -108,13 +108,13 @@ See [`upgrade`](https://nodejs.org/api/http.html#http_event_upgrade) | ||
- `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 | ||
- `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 | ||
- `onReq(req, options)`: Called before proxy request. Note you cannot keep a reference to the options object as it will be re-used by `http2-proxy`. | ||
- `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, resOrSocket)`: 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) | ||
- `resOrSocket`: For `web` [`http.ServerResponse`](https://nodejs.org/api/http.html#http_http_request_options_callback) or [`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverresponse) and for `ws` [`net.Socket`](https://nodejs.org/api/net.html#net_class_net_socket) | ||
- `options`: Options passed to [`http.request(options)`](https://nodejs.org/api/http.html#http_http_request_options_callback). | ||
- `onRes(req, resOrSocket)`: 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). | ||
- `resOrSocket`: For `web` [`http.ServerResponse`](https://nodejs.org/api/http.html#http_http_request_options_callback) or [`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#http2_class_http2_http2serverresponse) and for `ws` [`net.Socket`](https://nodejs.org/api/net.html#net_class_net_socket). | ||
@@ -121,0 +121,0 @@ ### License |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3
19291
406