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

front-express-http-proxy

Package Overview
Dependencies
Maintainers
7
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

front-express-http-proxy - npm Package Compare versions

Comparing version 0.11.0-2 to 1.6.2-1

.eslintignore

373

index.js
'use strict';
// * Breaks proxying into a series of discrete steps, many of which can be swapped out by authors.
// * Uses Promises to support async.
// * Uses a quasi-Global called Container to tidy up the argument passing between the major work-flow steps.
var ScopeContainer = require('./lib/scopeContainer');
var assert = require('assert');
var url = require('url');
var http = require('http');
var https = require('https');
var getRawBody = require('raw-body');
var zlib = require('zlib');
var debug = require('debug')('express-http-proxy');
var buildProxyReq = require('./app/steps/buildProxyReq');
var copyProxyResHeadersToUserRes = require('./app/steps/copyProxyResHeadersToUserRes');
var decorateProxyReqBody = require('./app/steps/decorateProxyReqBody');
var decorateProxyReqOpts = require('./app/steps/decorateProxyReqOpts');
var decorateUserRes = require('./app/steps/decorateUserRes');
var decorateUserResHeaders = require('./app/steps/decorateUserResHeaders');
var filterUserRequest = require('./app/steps/filterUserRequest');
var handleProxyErrors = require('./app/steps/handleProxyErrors');
var maybeSkipToNextHandler = require('./app/steps/maybeSkipToNextHandler');
var prepareProxyReq = require('./app/steps/prepareProxyReq');
var resolveProxyHost = require('./app/steps/resolveProxyHost');
var resolveProxyReqPath = require('./app/steps/resolveProxyReqPath');
var sendProxyRequest = require('./app/steps/sendProxyRequest');
var sendUserRes = require('./app/steps/sendUserRes');
function unset(val) {
return (typeof val === 'undefined' || val === '' || val === null);
}
module.exports = function proxy(host, options) {
module.exports = function proxy(host, userOptions) {
assert(host, 'Host should not be empty');
options = options || {};
var parsedHost;
/**
* Function :: intercept(targetResponse, data, res, req, function(err, json, sent));
*/
var intercept = options.intercept;
var decorateRequest = options.decorateRequest;
var forwardPath = options.forwardPath || defaultForwardPath;
var resolveProxyPathAsync = options.forwardPathAsync || defaultForwardPathAsync(forwardPath);
var filter = options.filter || defaultFilter;
var limit = options.limit || '1mb';
var preserveReqSession = options.preserveReqSession;
var memoizeHost = unset(options.memoizeHost) ? true : options.memoizeHost;
var rejectUnauthorized = !options.skipCertificateValidation;
return function handleProxy(req, res, next) {
if (!filter(req, res)) { return next(); }
var resolvePath = resolveProxyPathAsync(req, res);
var parseBody = maybeParseBody(req, limit);
var prepareRequest = Promise.all([resolvePath, parseBody]);
prepareRequest.then(function(results) {
var path = results[0];
var bodyContent = results[1];
sendProxyRequest(req, res, next, path, bodyContent);
});
};
debug('[start proxy] ' + req.path);
var container = new ScopeContainer(req, res, next, host, userOptions);
function sendProxyRequest(req, res, next, path, bodyContent) {
parsedHost = (memoizeHost && parsedHost) ? parsedHost : parseHost(host, req, options);
filterUserRequest(container)
.then(buildProxyReq)
.then(resolveProxyHost)
.then(decorateProxyReqOpts)
.then(resolveProxyReqPath)
.then(decorateProxyReqBody)
.then(prepareProxyReq)
.then(sendProxyRequest)
.then(maybeSkipToNextHandler)
.then(copyProxyResHeadersToUserRes)
.then(decorateUserResHeaders)
.then(decorateUserRes)
.then(sendUserRes)
.catch(function (err) {
// I sometimes reject without an error to shortcircuit the remaining
// steps and return control to the host application.
var reqOpt = {
hostname: parsedHost.host,
port: options.port || parsedHost.port,
headers: reqHeaders(req, options),
method: req.method,
path: path,
bodyContent: bodyContent,
params: req.params,
rejectUnauthorized
};
if (preserveReqSession) {
reqOpt.session = req.session;
}
if (decorateRequest) {
reqOpt = decorateRequest(reqOpt, req) || reqOpt;
}
bodyContent = reqOpt.bodyContent;
delete reqOpt.bodyContent;
delete reqOpt.params;
bodyContent = options.reqAsBuffer ?
asBuffer(bodyContent, options) :
asBufferOrString(bodyContent);
reqOpt.headers['content-length'] = getContentLength(bodyContent);
if (bodyEncoding(options)) {
reqOpt.headers['Accept-Charset'] = bodyEncoding(options);
}
function postIntercept(res, next, rspData) {
return function(err, rspd, sent) {
if (err) {
return next(err);
}
rspd = asBuffer(rspd, options);
rspd = maybeZipResponse(rspd, res);
if (!Buffer.isBuffer(rspd)) {
next(new Error('intercept should return string or' +
'buffer as data'));
}
if (!res.headersSent) {
res.set('content-length', rspd.length);
} else if (rspd.length !== rspData.length) {
var error = '"Content-Length" is already sent,' +
'the length of response data can not be changed';
next(new Error(error));
}
if (!sent) {
res.send(rspd);
}
};
}
var proxyTargetRequest = parsedHost.module.request(reqOpt, function(rsp) {
var chunks = [];
rsp.on('data', function(chunk) {
chunks.push(chunk);
});
rsp.on('end', function() {
var rspData = Buffer.concat(chunks, chunkLength(chunks));
if (intercept) {
rspData = maybeUnzipResponse(rspData, res);
var callback = postIntercept(res, next, rspData);
intercept(rsp, rspData, req, res, callback);
var resolver = (container.options.proxyErrorHandler) ?
container.options.proxyErrorHandler :
handleProxyErrors;
resolver(err, res, next);
} else {
// see issue https://github.com/villadora/express-http-proxy/issues/104
// Not sure how to automate tests on this line, so be careful when changing.
if (!res.headersSent) {
res.send(rspData);
}
next();
}
});
rsp.on('error', function(err) {
next(err);
});
if (!res.headersSent) {
res.status(rsp.statusCode);
Object.keys(rsp.headers)
.filter(function(item) { return item !== 'transfer-encoding'; })
.forEach(function(item) {
res.set(item, rsp.headers[item]);
});
}
});
proxyTargetRequest.on('socket', function(socket) {
if (options.timeout) {
socket.setTimeout(options.timeout, function() {
proxyTargetRequest.abort();
});
}
});
proxyTargetRequest.on('error', function(err) {
if (err.code === 'ECONNRESET') {
res.setHeader('X-Timout-Reason',
'express-http-proxy timed out your request after ' +
options.timeout + 'ms.');
res.writeHead(504, {'Content-Type': 'text/plain'});
res.end();
} else {
next(err);
}
});
if (bodyContent.length) {
proxyTargetRequest.write(bodyContent);
}
proxyTargetRequest.end();
req.on('aborted', function() {
proxyTargetRequest.abort();
});
}
};
};
function extend(obj, source, skips) {
if (!source) {
return obj;
}
for (var prop in source) {
if (!skips || skips.indexOf(prop) === -1) {
obj[prop] = source[prop];
}
}
return obj;
}
function parseHost(host, req, options) {
host = (typeof host === 'function') ? host(req) : host.toString();
if (!host) {
return new Error('Empty host parameter');
}
if (!/http(s)?:\/\//.test(host)) {
host = 'http://' + host;
}
var parsed = url.parse(host);
if (!parsed.hostname) {
return new Error('Unable to parse hostname, possibly missing protocol://?');
}
var ishttps = options.https || parsed.protocol === 'https:';
return {
host: parsed.hostname,
port: parsed.port || (ishttps ? 443 : 80),
module: ishttps ? https : http,
};
}
function reqHeaders(req, options) {
var headers = options.headers || {};
var skipHdrs = [ 'connection', 'content-length' ];
if (!options.preserveHostHdr) {
skipHdrs.push('host');
}
var hds = extend(headers, req.headers, skipHdrs);
hds.connection = 'close';
return hds;
}
function defaultFilter() {
// No-op version of filter. Allows everything!
return true;
}
function defaultForwardPath(req) {
return url.parse(req.url).path;
}
function bodyEncoding(options) {
/* For reqBodyEncoding, these is a meaningful difference between null and
* undefined. null should be passed forward as the value of reqBodyEncoding,
* and undefined should result in utf-8.
*/
return options.reqBodyEncoding !== undefined ? options.reqBodyEncoding: 'utf-8';
}
function chunkLength(chunks) {
return chunks.reduce(function(len, buf) {
return len + buf.length;
}, 0);
}
function defaultForwardPathAsync(forwardPath) {
return function(req, res) {
return new Promise(function(resolve) {
resolve(forwardPath(req, res));
});
};
}
function asBuffer(body, options) {
var ret;
if (Buffer.isBuffer(body)) {
ret = body;
} else if (typeof body === 'object') {
ret = new Buffer(JSON.stringify(body), bodyEncoding(options));
} else if (typeof body === 'string') {
ret = new Buffer(body, bodyEncoding(options));
}
return ret;
}
function asBufferOrString(body) {
var ret;
if (Buffer.isBuffer(body)) {
ret = body;
} else if (typeof body === 'object') {
ret = JSON.stringify(body);
} else if (typeof body === 'string') {
ret = body;
}
return ret;
}
function getContentLength(body) {
var result;
if (Buffer.isBuffer(body)) { // Buffer
result = body.length;
} else if (typeof body === 'string') {
result = Buffer.byteLength(body);
}
return result;
}
function isResGzipped(res) {
return res._headers['content-encoding'] === 'gzip';
}
function zipOrUnzip(method) {
return function(rspData, res) {
return (isResGzipped(res)) ? zlib[method](rspData) : rspData;
};
}
function maybeParseBody(req, limit) {
var promise;
if (req._body && req.body) {
promise = new Promise(function(resolve) {
resolve(req.body);
});
} else {
// Returns a promise if no callback specified and global Promise exists.
promise = getRawBody(req, {
length: req.headers['content-length'],
limit: limit,
});
}
return promise;
}
var maybeUnzipResponse = zipOrUnzip('gunzipSync');
var maybeZipResponse = zipOrUnzip('gzipSync');

@@ -0,1 +1,3 @@

'use strict';
var app = require('express')();

@@ -2,0 +4,0 @@

{
"name": "front-express-http-proxy",
"version": "0.11.0-2",
"version": "1.6.2-1",
"description": "http proxy middleware for express",
"engines": {
"node": ">=4.0.0"
"node": ">=6.0.0"
},
"engineStrict": true,
"main": "index.js",
"scripts": {
"test": "npm -s run mocha && npm run -s lint && npm run -s jscs",
"test:debug": "mocha debug -R spec test/*.js",
"mocha": "mocha -R spec test/*.js",
"lint": "jshint index.js test/*.js",
"jscs": "jscs index.js test/*.js"
"test": "npm -s run mocha && npm run -s lint",
"test:debug": "mocha debug -R spec test --recursive --exit",
"mocha": "mocha -R spec test --recursive --exit",
"lint": "eslint index.js **/*js"
},

@@ -33,12 +31,15 @@ "repository": {

"devDependencies": {
"body-parser": "^1.15.2",
"express": "^4.3.1",
"jscs": "^3.0.7",
"jshint": "^2.5.5",
"mocha": "^2.1.0",
"supertest": "^1.2.0"
"body-parser": "^1.17.2",
"chai": "^4.1.2",
"cookie-parser": "^1.4.3",
"eslint": "^4.19.1",
"express": "^4.15.4",
"mocha": "^8.0.1",
"nock": "^10.0.6",
"supertest": "^3.4.2"
},
"dependencies": {
"es6-promise": "^3.2.1",
"raw-body": "^2.1.7"
"debug": "^3.0.1",
"es6-promise": "^4.1.1",
"raw-body": "^2.3.0"
},

@@ -45,0 +46,0 @@ "contributors": [

@@ -1,5 +0,6 @@

# express-http-proxy [![NPM version](https://badge.fury.io/js/express-http-proxy.svg)](http://badge.fury.io/js/express-http-proxy) [![Build Status](https://travis-ci.org/villadora/express-http-proxy.svg?branch=master)](https://travis-ci.org/villadora/express-http-proxy) [![Dependency Status](https://gemnasium.com/villadora/express-http-proxy.svg)](https://gemnasium.com/villadora/express-http-proxy)
# express-http-proxy [![NPM version](https://badge.fury.io/js/express-http-proxy.svg)](http://badge.fury.io/js/express-http-proxy) [![Build Status](https://travis-ci.org/villadora/express-http-proxy.svg?branch=master)](https://travis-ci.org/villadora/express-http-proxy)
Express proxy middleware to forward request to another host and pass response back
Express middleware to proxy request to another host and pass response back to original caller.
## Install

@@ -16,2 +17,3 @@

### Example:
To proxy URLS starting with '/proxy' to the host 'www.google.com':

@@ -21,3 +23,2 @@

var proxy = require('express-http-proxy');
var app = require('express')();

@@ -28,32 +29,100 @@

### Options
### Streaming
Proxy requests and user responses are piped/streamed/chunked by default.
If you define a response modifier (userResDecorator, userResHeaderDecorator),
or need to inspect the response before continuing (maybeSkipToNext), streaming
is disabled, and the request and response are buffered.
This can cause performance issues with large payloads.
#### forwardPath
### Promises
The ```forwardPath``` option allows you to modify the path prior to proxying the request.
Many function hooks support Promises.
If any Promise is rejected, ```next(x)``` is called in the hosting application, where ```x``` is whatever you pass to ```Promise.reject```;
e.g.
```js
var proxy = require('express-http-proxy');
app.use(proxy('/reject-promise', {
proxyReqOptDecorator: function() {
return Promise.reject('An arbitrary rejection message.');
}
}));
```
var app = require('express')();
eventually calls
app.use('/proxy', proxy('www.google.com', {
forwardPath: function(req, res) {
return require('url').parse(req.url).path;
}
}));
```js
next('An arbitrary rejection messasage');
```
#### forwardPathAsync
The ```forwardPathAsync``` options allows you to modify the path asyncronously prior to proxying the request, using Promises.
### Host
The first positional argument is for the proxy host; in many cases you will use a static string here, eg.
```js
app.use(proxy('httpbin.org', {
forwardPathAsync: function() {
return new Promise(function(resolve, reject) {
// ...
// eventually
resolve( /* your resolved forwardPath as string */ )
app.use('/', proxy('http://google.com'))
```
However, this argument can also be a function, and that function can be
memoized or computed on each request, based on the setting of
```memoizeHost```.
```js
function selectProxyHost() {
return (new Date() % 2) ? 'http://google.com' : 'http://altavista.com';
}
app.use('/', proxy(selectProxyHost));
```
### Middleware mixing
If you use 'https://www.npmjs.com/package/body-parser' you should declare it AFTER the proxy configuration, otherwise original 'POST' body could be modified and not proxied correctly.
```
app.use('/proxy', 'http://foo.bar.com')
// Declare use of body-parser AFTER the use of proxy
app.use(bodyParser.foo(bar))
app.use('/api', ...)
```
### Options
#### proxyReqPathResolver (supports Promises)
Note: In ```express-http-proxy```, the ```path``` is considered the portion of
the url after the host, and including all query params. E.g. for the URL
```http://smoogle.com/search/path?q=123```; the path is
```/search/path?q=123```. Authors using this resolver must also handle the query parameter portion of the path.
Provide a proxyReqPathResolver function if you'd like to
operate on the path before issuing the proxy request. Use a Promise for async
operations.
```js
app.use(proxy('localhost:12345', {
proxyReqPathResolver: function (req) {
var parts = req.url.split('?');
var queryString = parts[1];
var updatedPath = parts[0].replace(/test/, 'tent');
return updatedPath + (queryString ? '?' + queryString : '');
}
}));
```
Promise form
```js
app.use('/proxy', proxy('localhost:12345', {
proxyReqPathResolver: function(req) {
return new Promise(function (resolve, reject) {
setTimeout(function () { // simulate async
var parts = req.url.split('?');
var queryString = parts[1];
var updatedPath = parts[0].replace(/test/, 'tent');
var resolvedPathValue = updatedPath + (queryString ? '?' + queryString : '');
resolve(resolvedPathValue);
}, 200);
});

@@ -64,6 +133,18 @@ }

#### filter
#### forwardPath
The ```filter``` option can be used to limit what requests are proxied. For example, if you only want to proxy get request
DEPRECATED. See proxyReqPathResolver
#### forwardPathAsync
DEPRECATED. See proxyReqPathResolver
#### filter (supports Promises)
The ```filter``` option can be used to limit what requests are proxied. Return
```true``` to continue to execute proxy; return false-y to skip proxy for this
request.
For example, if you only want to proxy get request:
```js

@@ -73,5 +154,2 @@ app.use('/proxy', proxy('www.google.com', {

return req.method == 'GET';
},
forwardPath: function(req, res) {
return require('url').parse(req.url).path;
}

@@ -81,12 +159,28 @@ }));

#### intercept
Promise form:
You can intercept the response before sending it back to the client.
```js
app.use(proxy('localhost:12346', {
filter: function (req, res) {
return new Promise(function (resolve) {
resolve(req.method === 'GET');
});
}
}));
```
Note that in the previous example, `resolve(false)` will execute the happy path
for filter here (skipping the rest of the proxy, and calling `next()`).
`reject()` will also skip the rest of proxy and call `next()`.
#### userResDecorator (was: intercept) (supports Promise)
You can modify the proxy's response before sending it to the client.
```js
app.use('/proxy', proxy('www.google.com', {
intercept: function(rsp, data, req, res, callback) {
// rsp - original response from the target
data = JSON.parse(data.toString('utf8'));
callback(null, JSON.stringify(data));
userResDecorator: function(proxyRes, proxyResData, userReq, userRes) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
return JSON.stringify(data);
}

@@ -96,2 +190,35 @@ }));

```js
app.use(proxy('httpbin.org', {
userResDecorator: function(proxyRes, proxyResData) {
return new Promise(function(resolve) {
proxyResData.funkyMessage = 'oi io oo ii';
setTimeout(function() {
resolve(proxyResData);
}, 200);
});
}
}));
```
##### 304 - Not Modified
When your proxied service returns 304, not modified, this step will be skipped, since there is no body to decorate.
##### exploiting references
The intent is that this be used to modify the proxy response data only.
Note:
The other arguments (proxyRes, userReq, userRes) are passed by reference, so
you *can* currently exploit this to modify either response's headers, for
instance, but this is not a reliable interface. I expect to close this
exploit in a future release, while providing an additional hook for mutating
the userRes before sending.
##### gzip responses
If your proxy response is gzipped, this program will automatically unzip
it before passing to your function, then zip it back up before piping it to the
user response. There is currently no way to short-circuit this behavior.
#### limit

@@ -114,3 +241,3 @@

When true, the ```host``` argument will be parsed on first request, and
memoized for all subsequent requests.
memoized for subsequent requests.

@@ -139,25 +266,132 @@ When ```false```, ```host``` argument will be parsed on each request.

### userResHeaderDecorator
When a `userResHeaderDecorator` is defined, the return of this method will replace (rather than be merged on to) the headers for `userRes`.
```js
app.use('/proxy', proxy('www.google.com', {
userResHeaderDecorator(headers, userReq, userRes, proxyReq, proxyRes) {
// recieves an Object of headers, returns an Object of headers.
return headers;
}
}));
```
#### decorateRequest
You can change the request options before it is sent to the target.
REMOVED: See ```proxyReqOptDecorator``` and ```proxyReqBodyDecorator```.
#### skipToNextHandlerFilter(supports Promise form)
(experimental: this interface may change in upcoming versions)
Allows you to inspect the proxy response, and decide if you want to continue processing (via express-http-proxy) or call ```next()``` to return control to express.
```js
app.use('/proxy', proxy('www.google.com', {
decorateRequest: function(proxyReq, originalReq) {
skipToNextHandlerFilter: function(proxyRes) {
return proxyRes.statusCode === 404;
}
}));
```
### proxyErrorHandler
By default, ```express-http-proxy``` will pass any errors except ECONNRESET to
next, so that your application can handle or react to them, or just drop
through to your default error handling. ECONNRESET errors are immediately
returned to the user for historical reasons.
If you would like to modify this behavior, you can provide your own ```proxyErrorHandler```.
```js
// Example of skipping all error handling.
app.use(proxy('localhost:12346', {
proxyErrorHandler: function(err, res, next) {
next(err);
}
}));
// Example of rolling your own
app.use(proxy('localhost:12346', {
proxyErrorHandler: function(err, res, next) {
switch (err && err.code) {
case 'ECONNRESET': { return res.status(405).send('504 became 405'); }
case 'ECONNREFUSED': { return res.status(200).send('gotcher back'); }
default: { next(err); }
}
}}));
```
#### proxyReqOptDecorator (supports Promise form)
You can override most request options before issuing the proxyRequest.
proxyReqOpt represents the options argument passed to the (http|https).request
module.
NOTE: req.path cannot be changed via this method; use ```proxyReqPathResolver``` instead. (see https://github.com/villadora/express-http-proxy/issues/243)
```js
app.use('/proxy', proxy('www.google.com', {
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
// you can update headers
proxyReq.headers['Content-Type'] = 'text/html';
proxyReqOpts.headers['Content-Type'] = 'text/html';
// you can change the method
proxyReq.method = 'GET';
// you can munge the bodyContent.
proxyReq.bodyContent = proxyReq.bodyContent.replace(/losing/, 'winning!');
return proxyReq;
proxyReqOpts.method = 'GET';
return proxyReqOpts;
}
}));
```
You can use a Promise for async style.
```js
app.use('/proxy', proxy('www.google.com', {
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
return new Promise(function(resolve, reject) {
proxyReqOpts.headers['Content-Type'] = 'text/html';
resolve(proxyReqOpts);
})
}
}));
```
#### proxyReqBodyDecorator (supports Promise form)
You can mutate the body content before sending the proxyRequest.
```js
app.use('/proxy', proxy('www.google.com', {
proxyReqBodyDecorator: function(bodyContent, srcReq) {
return bodyContent.split('').reverse().join('');
}
}));
```
You can use a Promise for async style.
```js
app.use('/proxy', proxy('www.google.com', {
proxyReqBodyDecorator: function(proxyReq, srcReq) {
return new Promise(function(resolve, reject) {
http.get('http://dev/null', function (err, res) {
if (err) { reject(err); }
resolve(res);
});
})
}
}));
```
#### https
Normally, your proxy request will be made on the same protocol as the original
request. If you'd like to force the proxy request to be https, use this
Normally, your proxy request will be made on the same protocol as the `host`
parameter. If you'd like to force the proxy request to be https, use this
option.

@@ -181,3 +415,35 @@

#### parseReqBody
The ```parseReqBody``` option allows you to control parsing the request body.
For example, disabling body parsing is useful for large uploads where it would be inefficient
to hold the data in memory.
##### Note: this setting is required for binary uploads. A future version of this library may handle this for you.
This defaults to true in order to preserve legacy behavior.
When false, no action will be taken on the body and accordingly ```req.body``` will no longer be set.
Note that setting this to false overrides ```reqAsBuffer``` and ```reqBodyEncoding``` below.
```js
app.use('/proxy', proxy('www.google.com', {
parseReqBody: false
}));
```
You can use function instead of boolean value for dynamic value generation based on request
```js
app.use('/proxy', proxy('www.google.com', {
parseReqBody: function (proxyReq) {
if (proxyReq.headers["content-type"] === "application/json") {
return true;
} else {
return false;
}
}
}));
```
#### reqAsBuffer

@@ -194,2 +460,4 @@

Ignored if ```parseReqBody``` is set to false.
```js

@@ -210,2 +478,4 @@ app.use('/proxy', proxy('www.google.com', {

Ignored if ```parseReqBody``` is set to false.
```js

@@ -217,6 +487,7 @@ app.use('/post', proxy('httpbin.org', {

#### timeout
By default, node does not express a timeout on connections. Use timeout option to impose a specific timeout. Timed-out requests will respond with 504 status code and a X-Timeout-Reason header.
By default, node does not express a timeout on connections.
Use timeout option to impose a specific timeout.
Timed-out requests will respond with 504 status code and a X-Timeout-Reason header.

@@ -229,28 +500,102 @@ ```js

## Trace debugging
## Questions
The node-debug module is used to provide a trace debugging capability.
### Q: Can it support https proxy?
```
DEBUG=express-http-proxy npm run YOUR_PROGRAM
DEBUG=express-http-proxy npm run YOUR_PROGRAM | grep 'express-http-proxy' # to filter down to just these messages
```
The library will use https if the provided path has 'https://' or ':443'. You can use decorateRequest to ammend any auth or challenge headers required to succeed https.
Will trace the execution of the express-http-proxy module in order to aide debugging.
Here is an older answer about using the https-proxy-agent package. It may be useful if the included functionality in ```http-express-proxy``` does not solve your use case.
A: Yes, you can use the 'https-proxy-agent' package. Something like this:
## Upgrade to 1.0, transition guide and breaking changes
1.
```decorateRequest``` has been REMOVED, and will generate an error when called. See ```proxyReqOptDecorator``` and ```proxyReqBodyDecorator```.
Resolution: Most authors will simply need to change the method name for their
decorateRequest method; if author was decorating reqOpts and reqBody in the
same method, this will need to be split up.
2.
```intercept``` has been REMOVED, and will generate an error when called. See ```userResDecorator```.
Resolution: Most authors will simply need to change the method name from ```intercept``` to ```userResDecorator```, and exit the method by returning the value, rather than passing it to a callback. E.g.:
Before:
```js
var corporateProxyServer = process.env.HTTP_PROXY || process.env.http_proxy || process.env.HTTPS_PROXY || process.env.https_proxy;
app.use('/proxy', proxy('www.google.com', {
intercept: function(proxyRes, proxyResData, userReq, userRes, cb) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
cb(null, JSON.stringify(data));
}
}));
```
if (corporateProxyServer) {
corporateProxyAgent = new HttpsProxyAgent(corporateProxyServer);
}
Now:
```js
app.use('/proxy', proxy('www.google.com', {
userResDecorator: function(proxyRes, proxyResData, userReq, userRes) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
return JSON.stringify(data);
}
}));
```
Then inside the decorateRequest method, add the agent to the request:
3.
```forwardPath``` and ```forwardPathAsync``` have been DEPRECATED and will generate a warning when called. See ```proxyReqPathResolver```.
Resolution: Simple update the name of either ```forwardPath``` or ```forwardPathAsync``` to ```proxyReqPathResolver```.
## When errors occur on your proxy server
When your proxy server responds with an error, express-http-proxy returns a response with the same status code. See ```test/catchingErrors``` for syntax details.
When your proxy server times out, express-http-proxy will continue to wait indefinitely for a response, unless you define a ```timeout``` as described above.
## Questions
### Q: Does it support https proxy?
The library will automatically use https if the provided path has 'https://' or ':443'. You may also set option ```https``` to true to always use https.
You can use ```proxyReqOptDecorator``` to ammend any auth or challenge headers required to succeed https.
### Q: How can I support non-standard certificate chains?
You can use the ability to decorate the proxy request prior to sending. See ```proxyReqOptDecorator``` for more details.
```js
req.agent = corporateProxyAgent;
app.use('/', proxy('internalhost.example.com', {
proxyReqOptDecorator: function(proxyReqOpts, originalReq) {
proxyReqOpts.ca = [caCert, intermediaryCert]
return proxyReqOpts;
}
})
```
### Q: How to ignore self-signed certificates ?
You can set the `rejectUnauthorized` value in proxy request options prior to sending. See ```proxyReqOptDecorator``` for more details.
```js
app.use('/', proxy('internalhost.example.com', {
proxyReqOptDecorator: function(proxyReqOpts, originalReq) {
proxyReqOpts.rejectUnauthorized = false
return proxyReqOpts;
}
}))
```
## Release Notes

@@ -260,3 +605,20 @@

| --- | --- |
| 0.11.1 | Allow author to prevent host from being memoized between requests. General program cleanup. |
| 1.6.2 | Update node.js versions used by ci. |
| 1.6.1 | Minor bug fixes and documentation. |
| 1.6.0 | Do gzip and gunzip aysyncronously. Test and documentation improvements, dependency updates. |
| 1.5.1 | Fixes bug in stringifying debug messages. |
| 1.5.0 | Fixes bug in `filter` signature. Fix bug in skipToNextHandler, add expressHttpProxy value to user res when skipped. Add tests for host as ip address. |
| 1.4.0 | DEPRECATED. Critical bug in the `filter` api.|
| 1.3.0 | DEPRECATED. Critical bug in the `filter` api. `filter` now supports Promises. Update linter to eslint. |
| 1.2.0 | Auto-stream when no decorations are made to req/res. Improved docs, fixes issues in maybeSkipToNexthandler, allow authors to manage error handling. |
| 1.1.0 | Add step to allow response headers to be modified.
| 1.0.7 | Update dependencies. Improve docs on promise rejection. Fix promise rejection on body limit. Improve debug output. |
| 1.0.6 | Fixes preserveHostHdr not working, skip userResDecorator on 304, add maybeSkipToNext, test improvements and cleanup. |
| 1.0.5 | Minor documentation and test patches |
| 1.0.4 | Minor documentation, test, and package fixes |
| 1.0.3 | Fixes 'limit option is not taken into account |
| 1.0.2 | Minor docs corrections. |
| 1.0.1 | Minor docs adjustments. |
| 1.0.0 | Major revision. <br > REMOVE decorateRequest, ADD proxyReqOptDecorator and proxyReqBodyDecorator. <br /> REMOVE intercept, ADD userResDecorator <br /> userResDecorator supports a Promise form for async operations. <br /> General cleanup of structure and application of hooks. Documentation improvements. Update all dependencies. Re-organize code as a series of workflow steps, each (potentially) supporting a promise, and creating a reusable pattern for future development. |
| 0.11.0 | Allow author to prevent host from being memoized between requests. General program cleanup. |
| 0.10.1| Fixed issue where 'body encoding' was being incorrectly set to the character encoding. <br /> Dropped explicit support for node 0.10. <br /> Intercept can now deal with gziped responses. <br /> Author can now 'force https', even if the original request is over http. <br /> Do not call next after ECONNRESET catch. |

@@ -263,0 +625,0 @@ | 0.10.0 | Fix regression in forwardPath implementation. |

@@ -0,1 +1,2 @@

'use strict';
var assert = require('assert');

@@ -7,37 +8,42 @@ var express = require('express');

var proxy = require('../');
var startProxyTarget = require('./support/proxyTarget');
describe('body encoding', function() {
'use strict';
this.timeout(10000);
var app;
describe('body encoding', function () {
var server;
beforeEach(function() {
app = express();
app.use(proxy('httpbin.org'));
before(function () {
server = startProxyTarget(8109, 1000);
});
after(function () {
server.close();
});
it('allow raw data', function(done) {
var pngHex = '89504e470d0a1a0a0' +
'000000d4948445200' +
'00000100000001080' +
'60000001f15c48900' +
'00000a49444154789' +
'c6300010000050001' +
'0d0a2db4000000004' +
'9454e44ae426082';
var pngData = new Buffer(pngHex, 'hex');
this.timeout(10000);
var pngHex = '89504e470d0a1a0a0' +
'000000d4948445200' +
'00000100000001080' +
'60000001f15c48900' +
'00000a49444154789' +
'c6300010000050001' +
'0d0a2db4000000004' +
'9454e44ae426082';
var pngData = new Buffer(pngHex, 'hex');
it('allow raw data', function (done) {
var filename = os.tmpdir() + '/express-http-proxy-test-' + (new Date()).getTime() + '-png-transparent.png';
var app = express();
app.use(proxy('httpbin.org', {
app.use(proxy('localhost:8109', {
reqBodyEncoding: null,
decorateRequest: function(reqOpts) {
assert((new Buffer(reqOpts.bodyContent).toString('hex')).indexOf(pngData.toString('hex')) >= 0,
proxyReqBodyDecorator: function (bodyContent) {
assert((new Buffer(bodyContent).toString('hex')).indexOf(pngData.toString('hex')) >= 0,
'body should contain same data');
return reqOpts;
return bodyContent;
}
}));
fs.writeFile(filename, pngData, function(err) {
fs.writeFile(filename, pngData, function (err) {
if (err) { throw err; }

@@ -47,5 +53,11 @@ request(app)

.attach('image', filename)
.end(function(err, res) {
fs.unlink(filename);
assert.equal(res.body.files.image, 'data:image/png;base64,' + pngData.toString('base64'));
.end(function (err) {
fs.unlinkSync(filename);
// This test is both broken and I think unnecessary.
// Its broken because http.bin no longer supports /post, but this test assertion is based on the old
// httpbin behavior.
// The assertion in the decorateRequest above verifies the test title.
//var response = new Buffer(res.body.attachment.data).toString('base64');
//assert(response.indexOf(pngData.toString('base64')) >= 0, 'response should include original raw data');
done(err);

@@ -57,7 +69,126 @@ });

describe('when user sets parseReqBody as bool', function () {
it('should not parse body', function (done) {
var filename = os.tmpdir() + '/express-http-proxy-test-' + (new Date()).getTime() + '-png-transparent.png';
var app = express();
app.use(proxy('localhost:8109', {
parseReqBody: false,
proxyReqBodyDecorator: function (bodyContent) {
assert(!bodyContent, 'body content should not be parsed.');
return bodyContent;
}
}));
describe('when user sets reqBodyEncoding', function() {
it('should set the accepts-charset header', function(done) {
fs.writeFile(filename, pngData, function (err) {
if (err) { throw err; }
request(app)
.post('/post')
.attach('image', filename)
.end(function (err) {
fs.unlinkSync(filename);
// This test is both broken and I think unnecessary.
// Its broken because http.bin no longer supports /post, but this test assertion is based on the old
// httpbin behavior.
// The assertion in the decorateRequest above verifies the test title.
// var response = new Buffer(res.body.attachment.data).toString('base64');
// assert(response.indexOf(pngData.toString('base64')) >= 0, 'response should include original raw data');
done(err);
});
});
});
it('should not fail on large limit', function (done) {
var filename = os.tmpdir() + '/express-http-proxy-test-' + (new Date()).getTime() + '-png-transparent.png';
var app = express();
app.use(proxy('httpbin.org', {
app.use(proxy('localhost:8109', {
parseReqBody: false,
limit: '20gb',
}));
fs.writeFile(filename, pngData, function (err) {
if (err) { throw err; }
request(app)
.post('/post')
.attach('image', filename)
.end(function (err) {
fs.unlinkSync(filename);
assert(err === null);
// This test is both broken and I think unnecessary.
// Its broken because http.bin no longer supports /post, but this test assertion is based on the old
// httpbin behavior.
// The assertion in the decorateRequest above verifies the test title.
//var response = new Buffer(res.body.attachment.data).toString('base64');
//assert(response.indexOf(pngData.toString('base64')) >= 0, 'response should include original raw data');
done(err);
});
});
});
it('should fail with an error when exceeding limit', function (done) {
var app = express();
app.use(proxy('localhost:8109', {
limit: 1,
}));
// silence jshint warning about unused vars - express error handler *needs* 4 args
app.use(function (err, req, res, next) { // eslint-disable-line no-unused-vars
res.json(err);
});
request(app)
.post('/post')
.send({ some: 'json' })
.end(function (err, response) {
assert(response.body.message === 'request entity too large');
done();
});
});
});
describe('when user sets parseReqBody as function', function () {
it('should not parse body with form-data content', function (done) {
var filename = os.tmpdir() + '/express-http-proxy-test-' + (new Date()).getTime() + '-png-transparent.png';
var app = express();
app.use(proxy('localhost:8109', {
parseReqBody: (proxyReq) => proxyReq.headers['content-type'].includes('application/json'),
proxyReqBodyDecorator: function (bodyContent) {
assert(!bodyContent, 'body content should not be parsed.');
return bodyContent;
}
}));
fs.writeFile(filename, pngData, function (err) {
if (err) { throw err; }
request(app)
.post('/post')
.attach('image', filename)
.end(function (err) {
fs.unlinkSync(filename);
done(err);
});
});
});
it('should parse body with json content', function (done) {
var app = express();
app.use(proxy('localhost:8109', {
parseReqBody: (proxyReq) => proxyReq.headers['content-type'].includes('application/json'),
proxyReqBodyDecorator: function (bodyContent) {
assert(bodyContent, 'body content should be parsed.');
return bodyContent;
}
}));
request(app)
.post('/post')
.send({ some: 'json' })
.end(function (err) {
done(err);
});
});
});
describe('when user sets reqBodyEncoding', function () {
it('should set the accepts-charset header', function (done) {
var app = express();
app.use(proxy('localhost:8109', {
reqBodyEncoding: 'utf-16'

@@ -67,5 +198,5 @@ }));

.get('/headers')
.end(function(err, res) {
.end(function (err, res) {
if (err) { throw err; }
assert.equal(res.body.headers['Accept-Charset'], 'utf-16');
assert.equal(res.body.headers['accept-charset'], 'utf-16');
done(err);

@@ -75,3 +206,4 @@ });

});
});

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,19 +8,39 @@ var express = require('express');

describe('proxies cookie', function() {
'use strict';
var proxyTarget = require('../test/support/proxyTarget');
var proxyRouteFn = [{
method: 'get',
path: '/cookieTest',
fn: function (req, res) {
Object.keys(req.cookies).forEach(function (key) {
res.cookie(key, req.cookies[key]);
});
res.sendStatus(200);
}
}];
describe('proxies cookie', function () {
this.timeout(10000);
var app;
var proxyServer;
beforeEach(function() {
beforeEach(function () {
proxyServer = proxyTarget(12346, 100, proxyRouteFn);
app = express();
app.use(proxy('httpbin.org'));
app.use(proxy('localhost:12346'));
});
it('set cookie', function(done) {
afterEach(function () {
proxyServer.close();
});
it('set cookie', function (done) {
request(app)
.get('/cookies/set?mycookie=value')
.end(function(err, res) {
assert(res.headers['set-cookie']);
.get('/cookieTest')
.set('Cookie', 'myApp-token=12345667')
.end(function (err, res) {
var cookiesMatch = res.headers['set-cookie'].filter(function (item) {
return item.match(/myApp-token=12345667/);
});
assert(cookiesMatch);
done(err);

@@ -25,0 +47,0 @@ });

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,4 +8,3 @@ var express = require('express');

describe('proxies headers', function() {
'use strict';
describe('proxies headers', function () {
this.timeout(10000);

@@ -13,3 +14,3 @@

beforeEach(function() {
beforeEach(function () {
http = express();

@@ -23,7 +24,7 @@ http.use(proxy('http://httpbin.org', {

it('passed as options', function(done) {
it('passed as options', function (done) {
request(http)
.get('/headers')
.expect(200)
.end(function(err, res) {
.end(function (err, res) {
if (err) { return done(err); }

@@ -35,3 +36,3 @@ assert(res.body.headers['X-Current-President'] === 'taft');

it('passed as on request', function(done) {
it('passed as on request', function (done) {
request(http)

@@ -41,3 +42,3 @@ .get('/headers')

.expect(200)
.end(function(err, res) {
.end(function (err, res) {
if (err) { return done(err); }

@@ -44,0 +45,0 @@ assert(res.body.headers['X-Powerererer']);

@@ -0,1 +1,3 @@

'use strict';
var express = require('express');

@@ -5,4 +7,3 @@ var request = require('supertest');

describe('host can be a dynamic function', function() {
'use strict';
describe('host can be a dynamic function', function () {

@@ -12,36 +13,60 @@ this.timeout(10000);

var app = express();
var firstProxyApp = express();
var secondProxyApp = express();
var firstPort = Math.floor(Math.random() * 10000);
var secondPort = Math.floor(Math.random() * 10000);
describe('and memoization can be disabled', function () {
var firstProxyApp = express();
var secondProxyApp = express();
// TODO: This seems like a bug factory. We will have intermittent port conflicts, yeah?
app.use('/proxy/:port', proxy(function(req) {
return 'localhost:' + req.params.port;
}, {
memoizeHost: false
}));
function randomNumberInPortRange() {
return Math.floor(Math.random() * 48000) + 1024;
}
var firstPort = randomNumberInPortRange();
var secondPort = randomNumberInPortRange();
firstProxyApp.get('/', function(req, res) {
res.sendStatus(204);
});
firstProxyApp.listen(firstPort);
var hostFn = function (req) {
return 'localhost:' + req.params.port;
};
secondProxyApp.get('/', function(req, res) {
res.sendStatus(200);
});
secondProxyApp.listen(secondPort);
app.use('/proxy/:port', proxy(hostFn, { memoizeHost: false }));
it('can proxy with session value', function(done) {
request(app)
.get('/proxy/' + firstPort)
.expect(204)
.end(function(err) {
if (err) {
return done(err);
}
request(app)
firstProxyApp
.get('/', function (req, res) { res.sendStatus(204); })
.listen(firstPort);
secondProxyApp
.get('/', function (req, res) { res.sendStatus(200); })
.listen(secondPort);
it('when not memoized, host resolves to a second value on the seecond call', function (done) {
request(app)
.get('/proxy/' + firstPort)
.expect(204)
.end(function (err) {
if (err) {
return done(err);
}
request(app)
.get('/proxy/' + secondPort)
.expect(200, done);
});
});
});
});
});
describe('host can be an ip address', function () {
it('with a port', function (done) {
var app = express();
app.use('/proxy/', proxy('127.0.0.1:3020'));
var targetApp = express();
targetApp
.get('/', function (req, res) { res.sendStatus(211); })
.listen(3020);
request(app)
.get('/proxy/')
.expect(211)
.end(done);
});
});

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,4 +8,3 @@ var express = require('express');

describe('proxies https', function() {
'use strict';
describe('proxies https', function () {

@@ -14,3 +15,3 @@ this.timeout(10000);

beforeEach(function() {
beforeEach(function () {
app = express();

@@ -22,6 +23,6 @@ });

.get('/get?show_env=1')
.end(function(err, res) {
.end(function (err, res) {
if (err) { return done(err); }
assert(res.body.headers['X-Forwarded-Ssl'] === 'on');
assert(res.body.headers['X-Forwarded-Protocol'] === 'https');
assert(res.body.headers['X-Forwarded-Port'] === '443', 'Expects forwarded 443 Port');
assert(res.body.headers['X-Forwarded-Proto'] === 'https', 'Expects forwarded protocol to be https');
done();

@@ -31,5 +32,5 @@ });

describe('when host is a String', function() {
describe('and includes "https" as protocol', function() {
it('proxys via https', function(done) {
describe('when host is a String', function () {
describe('and includes "https" as protocol', function () {
it('proxys via https', function (done) {
app.use(proxy('https://httpbin.org'));

@@ -39,5 +40,5 @@ assertSecureRequest(app, done);

});
describe('option https is set to "true"', function() {
it('proxys via https', function(done) {
app.use(proxy('http://httpbin.org', {https: true}));
describe('option https is set to "true"', function () {
it('proxys via https', function (done) {
app.use(proxy('http://httpbin.org', { https: true }));
assertSecureRequest(app, done);

@@ -48,12 +49,12 @@ });

describe('when host is a Function', function() {
describe('returned value includes "https" as protocol', function() {
it('proxys via https', function(done) {
app.use(proxy(function() { return 'https://httpbin.org'; }));
describe('when host is a Function', function () {
describe('returned value includes "https" as protocol', function () {
it('proxys via https', function (done) {
app.use(proxy(function () { return 'https://httpbin.org'; }));
assertSecureRequest(app, done);
});
});
describe('option https is set to "true"', function() {
it('proxys via https', function(done) {
app.use(proxy(function() { return 'http://httpbin.org'; }, {https: true}));
describe('option https is set to "true"', function () {
it('proxys via https', function (done) {
app.use(proxy(function () { return 'http://httpbin.org'; }, { https: true }));
assertSecureRequest(app, done);

@@ -60,0 +61,0 @@ });

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,10 +8,30 @@ var express = require('express');

var proxy = require('../');
var proxyTarget = require('../test/support/proxyTarget');
describe('middleware compatibility', function() {
'use strict';
it('should use req.body if defined', function(done) {
var proxyRouteFn = [{
method: 'post',
path: '/poster',
fn: function (req, res) {
res.send(req.body);
}
}];
describe('middleware compatibility', function () {
var proxyServer;
beforeEach(function () {
proxyServer = proxyTarget(12346, 100, proxyRouteFn);
});
afterEach(function () {
proxyServer.close();
});
it('should use req.body if defined', function (done) {
var app = express();
// Simulate another middleware that puts req stream into the body
app.use(function(req, res, next) {
app.use(function (req, res, next) {
var received = [];

@@ -28,8 +50,8 @@ req.on('data', function onData(chunk) {

app.use(proxy('httpbin.org', {
intercept: function(rsp, data, req, res, cb) {
app.use(proxy('localhost:12346', {
userResDecorator: function (rsp, data, req) {
assert(req.body);
assert.equal(req.body.foo, 1);
assert.equal(req.body.mypost, 'hello');
cb(null, data);
return data;
}

@@ -39,14 +61,12 @@ }));

request(app)
.post('/post')
.send({
mypost: 'hello'
.post('/poster')
.send({ mypost: 'hello' })
.expect(function (res) {
assert.equal(res.body.foo, 1);
assert.equal(res.body.mypost, 'hello');
})
.expect(function(res) {
assert.equal(res.body.json.foo, 1);
assert.equal(res.body.json.mypost, 'hello');
})
.end(done);
});
it('should stringify req.body when it is a json body so it is written to proxy request', function(done) {
it('should stringify req.body when it is a json body so it is written to proxy request', function (done) {
var app = express();

@@ -57,5 +77,5 @@ app.use(bodyParser.json());

}));
app.use(proxy('httpbin.org'));
app.use(proxy('localhost:12346'));
request(app)
.post('/post')
.post('/poster')
.send({

@@ -65,5 +85,5 @@ mypost: 'hello',

})
.expect(function(res) {
assert.equal(res.body.json.doorknob, 'wrect');
assert.equal(res.body.json.mypost, 'hello');
.expect(function (res) {
assert.equal(res.body.doorknob, 'wrect');
assert.equal(res.body.mypost, 'hello');
})

@@ -73,3 +93,3 @@ .end(done);

it('should convert req.body to a Buffer when reqAsBuffer is set', function(done) {
it('should convert req.body to a Buffer when reqAsBuffer is set', function (done) {
var app = express();

@@ -80,7 +100,7 @@ app.use(bodyParser.json());

}));
app.use(proxy('httpbin.org', {
app.use(proxy('localhost:12346', {
reqAsBuffer: true
}));
request(app)
.post('/post')
.post('/poster')
.send({

@@ -90,5 +110,5 @@ mypost: 'hello',

})
.expect(function(res) {
assert.equal(res.body.json.doorknob, 'wrect');
assert.equal(res.body.json.mypost, 'hello');
.expect(function (res) {
assert.equal(res.body.doorknob, 'wrect');
assert.equal(res.body.mypost, 'hello');
})

@@ -95,0 +115,0 @@ .end(done);

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -7,6 +9,5 @@ var express = require('express');

function proxyTarget(port) {
'use strict';
var other = express();
other.get('/', function(req, res) {
other.get('/', function (req, res) {
res.send('Success');

@@ -17,12 +18,12 @@ });

describe('proxies to requested port', function() {
'use strict';
describe('proxies to requested port', function () {
var other;
var http;
var other, http;
beforeEach(function() {
beforeEach(function () {
http = express();
other = proxyTarget(8080);
other = proxyTarget(56001);
});
afterEach(function() {
afterEach(function () {
other.close();

@@ -36,3 +37,3 @@ });

.expect(200)
.end(function(err, res) {
.end(function (err, res) {
if (err) { return done(err); }

@@ -44,7 +45,7 @@ assert(res.text === 'Success');

describe('when host is a String', function() {
it('when passed as an option', function(done) {
describe('when host is a String', function () {
it('when passed as an option', function (done) {
http.use(proxy('http://localhost', {
port: 8080
port: 56001
}));

@@ -55,5 +56,5 @@

it('when passed on the host string', function(done) {
it('when passed on the host string', function (done) {
http.use(proxy('http://localhost:8080'));
http.use(proxy('http://localhost:56001'));

@@ -65,9 +66,9 @@ assertSuccess(http, done);

describe('when host is a function', function() {
describe('when host is a function', function () {
it('and port is on the String returned', function(done) {
it('and port is on the String returned', function (done) {
http.use(proxy(
function() { return 'http://localhost:8080'; }
function () { return 'http://localhost:56001'; }
));

@@ -78,7 +79,7 @@

it('and port passed as an option', function(done) {
it('and port passed as an option', function (done) {
http.use(proxy(
function() { return 'http://localhost'; },
{ port: 8080 }
function () { return 'http://localhost'; },
{ port: 56001 }
));

@@ -85,0 +86,0 @@

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,4 +8,3 @@ var express = require('express');

describe('preserveReqSession', function() {
'use strict';
describe('preserveReqSession', function () {

@@ -14,3 +15,3 @@ this.timeout(10000);

beforeEach(function() {
beforeEach(function () {
app = express();

@@ -20,5 +21,5 @@ app.use(proxy('httpbin.org'));

it('preserveReqSession', function(done) {
it('preserveReqSession', function (done) {
var app = express();
app.use(function(req, res, next) {
app.use(function (req, res, next) {
req.session = 'hola';

@@ -29,4 +30,5 @@ next();

preserveReqSession: true,
decorateRequest: function(req) {
assert(req.session, 'hola');
proxyReqOptDecorator: function (reqOpts) {
assert(reqOpts.session, 'hola');
return reqOpts;
}

@@ -37,3 +39,3 @@ }));

.get('/user-agent')
.end(function(err) {
.end(function (err) {
if (err) { return done(err); }

@@ -40,0 +42,0 @@ done();

@@ -0,1 +1,3 @@

'use strict';
var express = require('express');

@@ -6,7 +8,5 @@ var request = require('supertest');

describe('proxies status code', function() {
'use strict';
describe('proxies status code', function () {
var proxyServer = express();
var port = 21231;
var port = 21239;
var proxiedEndpoint = 'http://localhost:' + port;

@@ -17,12 +17,12 @@ var server;

beforeEach(function() {
server = mockEndpoint.listen(21231);
beforeEach(function () {
server = mockEndpoint.listen(21239);
});
afterEach(function() {
afterEach(function () {
server.close();
});
[304, 404, 200, 401, 500].forEach(function(status) {
it('on ' + status, function(done) {
[304, 404, 200, 401, 500].forEach(function (status) {
it('on ' + status, function (done) {
request(proxyServer)

@@ -29,0 +29,0 @@ .get('/status/' + status)

@@ -1,27 +0,23 @@

var assert = require('assert');
'use strict';
var express = require('express');
var request = require('supertest');
var proxy = require('../');
var proxyTarget = require('./support/proxyTarget');
function proxyTarget(port, timeout) {
'use strict';
var other = express();
other.get('/', function(req, res) {
setTimeout(function() {
res.send('Success');
},timeout);
});
return other.listen(port);
}
describe('honors timeout option', function () {
describe('honors timeout option', function() {
'use strict';
var other;
var http;
var other, http;
beforeEach(function() {
beforeEach(function () {
http = express();
other = proxyTarget(8080, 1000);
other = proxyTarget(56001, 1000, [{
method: 'get',
path: '/',
fn: function (req, res) { res.sendStatus(200); }
}]);
});
afterEach(function() {
afterEach(function () {
other.close();

@@ -34,7 +30,3 @@ });

.expect(200)
.end(function(err, res) {
if (err) { return done(err); }
assert(res.text === 'Success');
done();
});
.end(done);
}

@@ -45,13 +37,11 @@

.get('/')
.expect(408)
.expect('X-Timout-Reason', 'express-http-proxy timed out your request after 100 ms.')
.end(function() {
done();
});
.expect(504)
.expect('X-Timeout-Reason', 'express-http-proxy reset the request.')
.end(done);
}
describe('when timeout option is set lower than server response time', function() {
it('should fail with CONNECTION TIMEOUT', function(done) {
describe('when timeout option is set lower than server response time', function () {
it('should fail with CONNECTION TIMEOUT', function (done) {
http.use(proxy('http://localhost:8080', {
http.use(proxy('http://localhost:56001', {
timeout: 100,

@@ -64,6 +54,6 @@ }));

describe('when timeout option is set higher than server response time', function() {
it('should succeed', function(done) {
describe('when timeout option is set higher than server response time', function () {
it('should succeed', function (done) {
http.use(proxy('http://localhost:8080', {
http.use(proxy('http://localhost:56001', {
timeout: 1200,

@@ -70,0 +60,0 @@ }));

@@ -0,1 +1,3 @@

'use strict';
var assert = require('assert');

@@ -6,8 +8,7 @@ var express = require('express');

describe('url parsing', function() {
'use strict';
describe('url parsing', function () {
this.timeout(10000);
it('can parse a url with a port', function(done) {
it('can parse a url with a port', function (done) {
var app = express();

@@ -17,3 +18,3 @@ app.use(proxy('http://httpbin.org:80'));

.get('/')
.end(function(err) {
.end(function (err) {
if (err) { return done(err); }

@@ -25,3 +26,3 @@ assert(true);

it('does not throw `Uncaught RangeError` if you have both a port and a trailing slash', function(done) {
it('does not throw `Uncaught RangeError` if you have both a port and a trailing slash', function (done) {
var app = express();

@@ -31,3 +32,3 @@ app.use(proxy('http://httpbin.org:80/'));

.get('/')
.end(function(err) {
.end(function (err) {
if (err) { return done(err); }

@@ -41,2 +42,1 @@ assert(true);

@@ -0,8 +1,10 @@

'use strict';
var assert = require('assert');
var express = require('express');
var bodyParser = require('body-parser');
var request = require('supertest');
var proxy = require('../');
describe('http verbs', function() {
'use strict';
describe('http verbs', function () {
this.timeout(10000);

@@ -12,11 +14,13 @@

beforeEach(function() {
beforeEach(function () {
app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(proxy('httpbin.org'));
});
it('test proxy get', function(done) {
it('test proxy get', function (done) {
request(app)
.get('/get')
.end(function(err, res) {
.end(function (err, res) {
if (err) { return done(err); }

@@ -29,3 +33,3 @@ assert(/node-superagent/.test(res.body.headers['User-Agent']));

it('test proxy post', function(done) {
it('test proxy post', function (done) {
request(app)

@@ -36,3 +40,3 @@ .post('/post')

})
.end(function(err, res) {
.end(function (err, res) {
assert.equal(res.body.data, '{"mypost":"hello"}');

@@ -43,4 +47,15 @@ done(err);

it('test proxy put', function(done) {
it('test proxy post by x-www-form-urlencoded', function (done) {
request(app)
.post('/post')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send('mypost=hello')
.end(function (err, res) {
assert.equal(JSON.stringify(res.body.form), '{"mypost":"hello"}');
done(err);
});
});
it('test proxy put', function (done) {
request(app)
.put('/put')

@@ -50,3 +65,3 @@ .send({

})
.end(function(err, res) {
.end(function (err, res) {
assert.equal(res.body.data, '{"mypost":"hello"}');

@@ -57,3 +72,3 @@ done(err);

it('test proxy patch', function(done) {
it('test proxy patch', function (done) {
request(app)

@@ -64,3 +79,3 @@ .patch('/patch')

})
.end(function(err, res) {
.end(function (err, res) {
assert.equal(res.body.data, '{"mypost":"hello"}');

@@ -71,3 +86,3 @@ done(err);

it('test proxy delete', function(done) {
it('test proxy delete', function (done) {
request(app)

@@ -78,3 +93,3 @@ .del('/delete')

})
.end(function(err, res) {
.end(function (err, res) {
assert.equal(res.body.data, '{"mypost":"hello"}');

@@ -81,0 +96,0 @@ done(err);

Sorry, the diff of this file is not supported yet

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