http-proxy-middleware 0.19.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -3
- package/README.md +58 -51
- package/dist/config-factory.js +79 -0
- package/dist/context-matcher.js +81 -0
- package/dist/errors.js +9 -0
- package/dist/handlers.js +70 -0
- package/dist/http-proxy-middleware.js +140 -0
- package/dist/index.js +7 -0
- package/dist/logger.js +135 -0
- package/dist/path-rewriter.js +67 -0
- package/dist/router.js +45 -0
- package/package.json +43 -31
- package/index.js +0 -5
- package/lib/config-factory.js +0 -129
- package/lib/context-matcher.js +0 -94
- package/lib/errors.js +0 -12
- package/lib/handlers.js +0 -82
- package/lib/index.js +0 -182
- package/lib/logger.js +0 -172
- package/lib/path-rewriter.js +0 -79
- package/lib/router.js +0 -51
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [v0.
|
|
4
|
-
|
|
5
|
-
-
|
|
3
|
+
## [v0.20.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.20.0)
|
|
4
|
+
|
|
5
|
+
- fix(ws): concurrent websocket requests do not get upgraded ([#335](https://github.com/chimurai/http-proxy-middleware/issues/335))
|
|
6
|
+
- chore: drop node 6 (BREAKING CHANGE)
|
|
7
|
+
- chore: update to micromatch@4 ([BREAKING CHANGE](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md#400---2019-03-20))
|
|
8
|
+
- chore: update dev dependencies
|
|
9
|
+
- refactor: migrate to typescript ([#328](https://github.com/chimurai/http-proxy-middleware/pull/328))
|
|
10
|
+
- feat(middleware): Promise / async support ([#328](https://github.com/chimurai/http-proxy-middleware/pull/328/files#diff-7890bfeb41abb0fc0ef2670749c84077R50))
|
|
11
|
+
- refactor: remove legacy options `proxyHost` and `proxyTable` (BREAKING CHANGE)
|
|
6
12
|
|
|
7
13
|
## [v0.19.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.19.1)
|
|
8
14
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://travis-ci.org/chimurai/http-proxy-middleware)
|
|
4
4
|
[](https://coveralls.io/r/chimurai/http-proxy-middleware)
|
|
5
5
|
[](https://david-dm.org/chimurai/http-proxy-middleware#info=dependencies)
|
|
6
|
-
[](https://snyk.io/test/npm/http-proxy-middleware)
|
|
6
|
+
[](https://snyk.io/test/npm/http-proxy-middleware)
|
|
7
7
|
[](https://github.com/prettier/prettier)
|
|
8
8
|
|
|
9
9
|
Node.js proxying made simple. Configure proxy middleware with ease for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express), [browser-sync](https://github.com/BrowserSync/browser-sync) and [many more](#compatible-servers).
|
|
@@ -15,13 +15,16 @@ Powered by the popular Nodejitsu [`http-proxy`](https://github.com/nodejitsu/nod
|
|
|
15
15
|
Proxy `/api` requests to `http://www.example.org`
|
|
16
16
|
|
|
17
17
|
```javascript
|
|
18
|
-
var express = require('express')
|
|
19
|
-
var proxy = require('http-proxy-middleware')
|
|
18
|
+
var express = require('express');
|
|
19
|
+
var proxy = require('http-proxy-middleware');
|
|
20
20
|
|
|
21
|
-
var app = express()
|
|
21
|
+
var app = express();
|
|
22
22
|
|
|
23
|
-
app.use(
|
|
24
|
-
|
|
23
|
+
app.use(
|
|
24
|
+
'/api',
|
|
25
|
+
proxy({ target: 'http://www.example.org', changeOrigin: true })
|
|
26
|
+
);
|
|
27
|
+
app.listen(3000);
|
|
25
28
|
|
|
26
29
|
// http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar
|
|
27
30
|
```
|
|
@@ -68,9 +71,9 @@ Proxy middleware configuration.
|
|
|
68
71
|
#### proxy([context,] config)
|
|
69
72
|
|
|
70
73
|
```javascript
|
|
71
|
-
var proxy = require('http-proxy-middleware')
|
|
74
|
+
var proxy = require('http-proxy-middleware');
|
|
72
75
|
|
|
73
|
-
var apiProxy = proxy('/api', { target: 'http://www.example.org' })
|
|
76
|
+
var apiProxy = proxy('/api', { target: 'http://www.example.org' });
|
|
74
77
|
// \____/ \_____________________________/
|
|
75
78
|
// | |
|
|
76
79
|
// context options
|
|
@@ -88,7 +91,7 @@ var apiProxy = proxy('/api', { target: 'http://www.example.org' })
|
|
|
88
91
|
|
|
89
92
|
```javascript
|
|
90
93
|
// shorthand syntax for the example above:
|
|
91
|
-
var apiProxy = proxy('http://www.example.org/api')
|
|
94
|
+
var apiProxy = proxy('http://www.example.org/api');
|
|
92
95
|
```
|
|
93
96
|
|
|
94
97
|
More about the [shorthand configuration](#shorthand).
|
|
@@ -99,8 +102,8 @@ An example with `express` server.
|
|
|
99
102
|
|
|
100
103
|
```javascript
|
|
101
104
|
// include dependencies
|
|
102
|
-
var express = require('express')
|
|
103
|
-
var proxy = require('http-proxy-middleware')
|
|
105
|
+
var express = require('express');
|
|
106
|
+
var proxy = require('http-proxy-middleware');
|
|
104
107
|
|
|
105
108
|
// proxy middleware options
|
|
106
109
|
var options = {
|
|
@@ -116,15 +119,15 @@ var options = {
|
|
|
116
119
|
// override target 'http://www.example.org' to 'http://localhost:8000'
|
|
117
120
|
'dev.localhost:3000': 'http://localhost:8000'
|
|
118
121
|
}
|
|
119
|
-
}
|
|
122
|
+
};
|
|
120
123
|
|
|
121
124
|
// create the proxy (without context)
|
|
122
|
-
var exampleProxy = proxy(options)
|
|
125
|
+
var exampleProxy = proxy(options);
|
|
123
126
|
|
|
124
127
|
// mount `exampleProxy` in web server
|
|
125
|
-
var app = express()
|
|
126
|
-
app.use('/api', exampleProxy)
|
|
127
|
-
app.listen(3000)
|
|
128
|
+
var app = express();
|
|
129
|
+
app.use('/api', exampleProxy);
|
|
130
|
+
app.listen(3000);
|
|
128
131
|
```
|
|
129
132
|
|
|
130
133
|
## Context matching
|
|
@@ -172,10 +175,10 @@ Providing an alternative way to decide which requests should be proxied; In case
|
|
|
172
175
|
* @return {Boolean}
|
|
173
176
|
*/
|
|
174
177
|
var filter = function(pathname, req) {
|
|
175
|
-
return pathname.match('^/api') && req.method === 'GET'
|
|
176
|
-
}
|
|
178
|
+
return pathname.match('^/api') && req.method === 'GET';
|
|
179
|
+
};
|
|
177
180
|
|
|
178
|
-
var apiProxy = proxy(filter, { target: 'http://www.example.org' })
|
|
181
|
+
var apiProxy = proxy(filter, { target: 'http://www.example.org' });
|
|
179
182
|
```
|
|
180
183
|
|
|
181
184
|
## Options
|
|
@@ -224,14 +227,14 @@ Providing an alternative way to decide which requests should be proxied; In case
|
|
|
224
227
|
// simple replace
|
|
225
228
|
function logProvider(provider) {
|
|
226
229
|
// replace the default console log provider.
|
|
227
|
-
return require('winston')
|
|
230
|
+
return require('winston');
|
|
228
231
|
}
|
|
229
232
|
```
|
|
230
233
|
|
|
231
234
|
```javascript
|
|
232
235
|
// verbose replacement
|
|
233
236
|
function logProvider(provider) {
|
|
234
|
-
var logger = new (require('winston')).Logger()
|
|
237
|
+
var logger = new (require('winston')).Logger();
|
|
235
238
|
|
|
236
239
|
var myCustomProvider = {
|
|
237
240
|
log: logger.log,
|
|
@@ -239,14 +242,11 @@ Providing an alternative way to decide which requests should be proxied; In case
|
|
|
239
242
|
info: logger.info,
|
|
240
243
|
warn: logger.warn,
|
|
241
244
|
error: logger.error
|
|
242
|
-
}
|
|
243
|
-
return myCustomProvider
|
|
245
|
+
};
|
|
246
|
+
return myCustomProvider;
|
|
244
247
|
}
|
|
245
248
|
```
|
|
246
249
|
|
|
247
|
-
- (DEPRECATED) **option.proxyHost**: Use `option.changeOrigin = true` instead.
|
|
248
|
-
- (DEPRECATED) **option.proxyTable**: Use `option.router` instead.
|
|
249
|
-
|
|
250
250
|
### http-proxy events
|
|
251
251
|
|
|
252
252
|
Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events):
|
|
@@ -257,10 +257,10 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
257
257
|
function onError(err, req, res) {
|
|
258
258
|
res.writeHead(500, {
|
|
259
259
|
'Content-Type': 'text/plain'
|
|
260
|
-
})
|
|
260
|
+
});
|
|
261
261
|
res.end(
|
|
262
262
|
'Something went wrong. And we are reporting a custom error message.'
|
|
263
|
-
)
|
|
263
|
+
);
|
|
264
264
|
}
|
|
265
265
|
```
|
|
266
266
|
|
|
@@ -268,8 +268,8 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
268
268
|
|
|
269
269
|
```javascript
|
|
270
270
|
function onProxyRes(proxyRes, req, res) {
|
|
271
|
-
proxyRes.headers['x-added'] = 'foobar' // add new header to response
|
|
272
|
-
delete proxyRes.headers['x-removed'] // remove header from response
|
|
271
|
+
proxyRes.headers['x-added'] = 'foobar'; // add new header to response
|
|
272
|
+
delete proxyRes.headers['x-removed']; // remove header from response
|
|
273
273
|
}
|
|
274
274
|
```
|
|
275
275
|
|
|
@@ -278,7 +278,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
278
278
|
```javascript
|
|
279
279
|
function onProxyReq(proxyReq, req, res) {
|
|
280
280
|
// add custom header to request
|
|
281
|
-
proxyReq.setHeader('x-added', 'foobar')
|
|
281
|
+
proxyReq.setHeader('x-added', 'foobar');
|
|
282
282
|
// or log the req
|
|
283
283
|
}
|
|
284
284
|
```
|
|
@@ -288,7 +288,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
288
288
|
```javascript
|
|
289
289
|
function onProxyReqWs(proxyReq, req, socket, options, head) {
|
|
290
290
|
// add custom header
|
|
291
|
-
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar')
|
|
291
|
+
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
|
|
292
292
|
}
|
|
293
293
|
```
|
|
294
294
|
|
|
@@ -297,7 +297,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
297
297
|
```javascript
|
|
298
298
|
function onOpen(proxySocket) {
|
|
299
299
|
// listen for messages coming FROM the target here
|
|
300
|
-
proxySocket.on('data', hybiParseAndLogMessage)
|
|
300
|
+
proxySocket.on('data', hybiParseAndLogMessage);
|
|
301
301
|
}
|
|
302
302
|
```
|
|
303
303
|
|
|
@@ -305,7 +305,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
305
305
|
```javascript
|
|
306
306
|
function onClose(res, socket, head) {
|
|
307
307
|
// view disconnected websocket connections
|
|
308
|
-
console.log('Client disconnected')
|
|
308
|
+
console.log('Client disconnected');
|
|
309
309
|
}
|
|
310
310
|
```
|
|
311
311
|
|
|
@@ -383,13 +383,13 @@ The following options are provided by the underlying [http-proxy](https://github
|
|
|
383
383
|
Use the shorthand syntax when verbose configuration is not needed. The `context` and `option.target` will be automatically configured when shorthand is used. Options can still be used if needed.
|
|
384
384
|
|
|
385
385
|
```javascript
|
|
386
|
-
proxy('http://www.example.org:8000/api')
|
|
386
|
+
proxy('http://www.example.org:8000/api');
|
|
387
387
|
// proxy('/api', {target: 'http://www.example.org:8000'});
|
|
388
388
|
|
|
389
|
-
proxy('http://www.example.org:8000/api/books/*/**.json')
|
|
389
|
+
proxy('http://www.example.org:8000/api/books/*/**.json');
|
|
390
390
|
// proxy('/api/books/*/**.json', {target: 'http://www.example.org:8000'});
|
|
391
391
|
|
|
392
|
-
proxy('http://www.example.org:8000/api', { changeOrigin: true })
|
|
392
|
+
proxy('http://www.example.org:8000/api', { changeOrigin: true });
|
|
393
393
|
// proxy('/api', {target: 'http://www.example.org:8000', changeOrigin: true});
|
|
394
394
|
```
|
|
395
395
|
|
|
@@ -399,7 +399,10 @@ If you want to use the server's `app.use` `path` parameter to match requests;
|
|
|
399
399
|
Create and mount the proxy without the http-proxy-middleware `context` parameter:
|
|
400
400
|
|
|
401
401
|
```javascript
|
|
402
|
-
app.use(
|
|
402
|
+
app.use(
|
|
403
|
+
'/api',
|
|
404
|
+
proxy({ target: 'http://www.example.org', changeOrigin: true })
|
|
405
|
+
);
|
|
403
406
|
```
|
|
404
407
|
|
|
405
408
|
`app.use` documentation:
|
|
@@ -411,13 +414,13 @@ app.use('/api', proxy({ target: 'http://www.example.org', changeOrigin: true }))
|
|
|
411
414
|
|
|
412
415
|
```javascript
|
|
413
416
|
// verbose api
|
|
414
|
-
proxy('/', { target: 'http://echo.websocket.org', ws: true })
|
|
417
|
+
proxy('/', { target: 'http://echo.websocket.org', ws: true });
|
|
415
418
|
|
|
416
419
|
// shorthand
|
|
417
|
-
proxy('http://echo.websocket.org', { ws: true })
|
|
420
|
+
proxy('http://echo.websocket.org', { ws: true });
|
|
418
421
|
|
|
419
422
|
// shorter shorthand
|
|
420
|
-
proxy('ws://echo.websocket.org')
|
|
423
|
+
proxy('ws://echo.websocket.org');
|
|
421
424
|
```
|
|
422
425
|
|
|
423
426
|
### External WebSocket upgrade
|
|
@@ -425,13 +428,13 @@ proxy('ws://echo.websocket.org')
|
|
|
425
428
|
In the previous WebSocket examples, http-proxy-middleware relies on a initial http request in order to listen to the http `upgrade` event. If you need to proxy WebSockets without the initial http request, you can subscribe to the server's http `upgrade` event manually.
|
|
426
429
|
|
|
427
430
|
```javascript
|
|
428
|
-
var wsProxy = proxy('ws://echo.websocket.org', { changeOrigin: true })
|
|
431
|
+
var wsProxy = proxy('ws://echo.websocket.org', { changeOrigin: true });
|
|
429
432
|
|
|
430
|
-
var app = express()
|
|
431
|
-
app.use(wsProxy)
|
|
433
|
+
var app = express();
|
|
434
|
+
app.use(wsProxy);
|
|
432
435
|
|
|
433
|
-
var server = app.listen(3000)
|
|
434
|
-
server.on('upgrade', wsProxy.upgrade) // <-- subscribe to http 'upgrade'
|
|
436
|
+
var server = app.listen(3000);
|
|
437
|
+
server.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'
|
|
435
438
|
```
|
|
436
439
|
|
|
437
440
|
## Working examples
|
|
@@ -468,16 +471,20 @@ Run the test suite:
|
|
|
468
471
|
|
|
469
472
|
```bash
|
|
470
473
|
# install dependencies
|
|
471
|
-
$
|
|
474
|
+
$ yarn
|
|
472
475
|
|
|
473
476
|
# linting
|
|
474
|
-
$
|
|
477
|
+
$ yarn lint
|
|
478
|
+
$ yarn lint:fix
|
|
479
|
+
|
|
480
|
+
# building (compile typescript to js)
|
|
481
|
+
$ yarn build
|
|
475
482
|
|
|
476
483
|
# unit tests
|
|
477
|
-
$
|
|
484
|
+
$ yarn test
|
|
478
485
|
|
|
479
486
|
# code coverage
|
|
480
|
-
$
|
|
487
|
+
$ yarn cover
|
|
481
488
|
```
|
|
482
489
|
|
|
483
490
|
## Changelog
|
|
@@ -488,4 +495,4 @@ $ npm run cover
|
|
|
488
495
|
|
|
489
496
|
The MIT License (MIT)
|
|
490
497
|
|
|
491
|
-
Copyright (c) 2015-
|
|
498
|
+
Copyright (c) 2015-2019 Steven Chim
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _ = require("lodash");
|
|
4
|
+
const url = require("url");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
const logger = logger_1.getInstance();
|
|
8
|
+
function createConfig(context, opts) {
|
|
9
|
+
// structure of config object to be returned
|
|
10
|
+
const config = {
|
|
11
|
+
context: undefined,
|
|
12
|
+
options: {}
|
|
13
|
+
};
|
|
14
|
+
// app.use('/api', proxy({target:'http://localhost:9000'}));
|
|
15
|
+
if (isContextless(context, opts)) {
|
|
16
|
+
config.context = '/';
|
|
17
|
+
config.options = _.assign(config.options, context);
|
|
18
|
+
// app.use('/api', proxy('http://localhost:9000'));
|
|
19
|
+
// app.use(proxy('http://localhost:9000/api'));
|
|
20
|
+
}
|
|
21
|
+
else if (isStringShortHand(context)) {
|
|
22
|
+
const oUrl = url.parse(context);
|
|
23
|
+
const target = [oUrl.protocol, '//', oUrl.host].join('');
|
|
24
|
+
config.context = oUrl.pathname || '/';
|
|
25
|
+
config.options = _.assign(config.options, { target }, opts);
|
|
26
|
+
if (oUrl.protocol === 'ws:' || oUrl.protocol === 'wss:') {
|
|
27
|
+
config.options.ws = true;
|
|
28
|
+
}
|
|
29
|
+
// app.use('/api', proxy({target:'http://localhost:9000'}));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
config.context = context;
|
|
33
|
+
config.options = _.assign(config.options, opts);
|
|
34
|
+
}
|
|
35
|
+
configureLogger(config.options);
|
|
36
|
+
if (!config.options.target) {
|
|
37
|
+
throw new Error(errors_1.ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING);
|
|
38
|
+
}
|
|
39
|
+
return config;
|
|
40
|
+
}
|
|
41
|
+
exports.createConfig = createConfig;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a String only target/config is provided.
|
|
44
|
+
* This can be just the host or with the optional path.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* app.use('/api', proxy('http://localhost:9000'));
|
|
48
|
+
* app.use(proxy('http://localhost:9000/api'));
|
|
49
|
+
*
|
|
50
|
+
* @param {String} context [description]
|
|
51
|
+
* @return {Boolean} [description]
|
|
52
|
+
*/
|
|
53
|
+
function isStringShortHand(context) {
|
|
54
|
+
if (_.isString(context)) {
|
|
55
|
+
return !!url.parse(context).host;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks if a Object only config is provided, without a context.
|
|
60
|
+
* In this case the all paths will be proxied.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* app.use('/api', proxy({target:'http://localhost:9000'}));
|
|
64
|
+
*
|
|
65
|
+
* @param {Object} context [description]
|
|
66
|
+
* @param {*} opts [description]
|
|
67
|
+
* @return {Boolean} [description]
|
|
68
|
+
*/
|
|
69
|
+
function isContextless(context, opts) {
|
|
70
|
+
return _.isPlainObject(context) && _.isEmpty(opts);
|
|
71
|
+
}
|
|
72
|
+
function configureLogger(options) {
|
|
73
|
+
if (options.logLevel) {
|
|
74
|
+
logger.setLevel(options.logLevel);
|
|
75
|
+
}
|
|
76
|
+
if (options.logProvider) {
|
|
77
|
+
logger.setProvider(options.logProvider);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const isGlob = require("is-glob");
|
|
4
|
+
const _ = require("lodash");
|
|
5
|
+
const micromatch = require("micromatch");
|
|
6
|
+
const url = require("url");
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
function match(context, uri, req) {
|
|
9
|
+
// single path
|
|
10
|
+
if (isStringPath(context)) {
|
|
11
|
+
return matchSingleStringPath(context, uri);
|
|
12
|
+
}
|
|
13
|
+
// single glob path
|
|
14
|
+
if (isGlobPath(context)) {
|
|
15
|
+
return matchSingleGlobPath(context, uri);
|
|
16
|
+
}
|
|
17
|
+
// multi path
|
|
18
|
+
if (Array.isArray(context)) {
|
|
19
|
+
if (context.every(isStringPath)) {
|
|
20
|
+
return matchMultiPath(context, uri);
|
|
21
|
+
}
|
|
22
|
+
if (context.every(isGlobPath)) {
|
|
23
|
+
return matchMultiGlobPath(context, uri);
|
|
24
|
+
}
|
|
25
|
+
throw new Error(errors_1.ERRORS.ERR_CONTEXT_MATCHER_INVALID_ARRAY);
|
|
26
|
+
}
|
|
27
|
+
// custom matching
|
|
28
|
+
if (_.isFunction(context)) {
|
|
29
|
+
const pathname = getUrlPathName(uri);
|
|
30
|
+
return context(pathname, req);
|
|
31
|
+
}
|
|
32
|
+
throw new Error(errors_1.ERRORS.ERR_CONTEXT_MATCHER_GENERIC);
|
|
33
|
+
}
|
|
34
|
+
exports.match = match;
|
|
35
|
+
/**
|
|
36
|
+
* @param {String} context '/api'
|
|
37
|
+
* @param {String} uri 'http://example.org/api/b/c/d.html'
|
|
38
|
+
* @return {Boolean}
|
|
39
|
+
*/
|
|
40
|
+
function matchSingleStringPath(context, uri) {
|
|
41
|
+
const pathname = getUrlPathName(uri);
|
|
42
|
+
return pathname.indexOf(context) === 0;
|
|
43
|
+
}
|
|
44
|
+
function matchSingleGlobPath(pattern, uri) {
|
|
45
|
+
const pathname = getUrlPathName(uri);
|
|
46
|
+
const matches = micromatch([pathname], pattern);
|
|
47
|
+
return matches && matches.length > 0;
|
|
48
|
+
}
|
|
49
|
+
function matchMultiGlobPath(patternList, uri) {
|
|
50
|
+
return matchSingleGlobPath(patternList, uri);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @param {String} contextList ['/api', '/ajax']
|
|
54
|
+
* @param {String} uri 'http://example.org/api/b/c/d.html'
|
|
55
|
+
* @return {Boolean}
|
|
56
|
+
*/
|
|
57
|
+
function matchMultiPath(contextList, uri) {
|
|
58
|
+
let isMultiPath = false;
|
|
59
|
+
for (const context of contextList) {
|
|
60
|
+
if (matchSingleStringPath(context, uri)) {
|
|
61
|
+
isMultiPath = true;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return isMultiPath;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parses URI and returns RFC 3986 path
|
|
69
|
+
*
|
|
70
|
+
* @param {String} uri from req.url
|
|
71
|
+
* @return {String} RFC 3986 path
|
|
72
|
+
*/
|
|
73
|
+
function getUrlPathName(uri) {
|
|
74
|
+
return uri && url.parse(uri).pathname;
|
|
75
|
+
}
|
|
76
|
+
function isStringPath(context) {
|
|
77
|
+
return _.isString(context) && !isGlob(context);
|
|
78
|
+
}
|
|
79
|
+
function isGlobPath(context) {
|
|
80
|
+
return isGlob(context);
|
|
81
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var ERRORS;
|
|
4
|
+
(function (ERRORS) {
|
|
5
|
+
ERRORS["ERR_CONFIG_FACTORY_TARGET_MISSING"] = "[HPM] Missing \"target\" option. Example: {target: \"http://www.example.org\"}";
|
|
6
|
+
ERRORS["ERR_CONTEXT_MATCHER_GENERIC"] = "[HPM] Invalid context. Expecting something like: \"/api\" or [\"/api\", \"/ajax\"]";
|
|
7
|
+
ERRORS["ERR_CONTEXT_MATCHER_INVALID_ARRAY"] = "[HPM] Invalid context. Expecting something like: [\"/api\", \"/ajax\"] or [\"/api/**\", \"!**.html\"]";
|
|
8
|
+
ERRORS["ERR_PATH_REWRITER_CONFIG"] = "[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function";
|
|
9
|
+
})(ERRORS = exports.ERRORS || (exports.ERRORS = {}));
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _ = require("lodash");
|
|
4
|
+
const logger_1 = require("./logger");
|
|
5
|
+
const logger = logger_1.getInstance();
|
|
6
|
+
function init(proxy, option) {
|
|
7
|
+
const handlers = getHandlers(option);
|
|
8
|
+
for (const eventName of Object.keys(handlers)) {
|
|
9
|
+
proxy.on(eventName, handlers[eventName]);
|
|
10
|
+
}
|
|
11
|
+
logger.debug('[HPM] Subscribed to http-proxy events:', Object.keys(handlers));
|
|
12
|
+
}
|
|
13
|
+
exports.init = init;
|
|
14
|
+
function getHandlers(options) {
|
|
15
|
+
// https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events
|
|
16
|
+
const proxyEvents = [
|
|
17
|
+
'error',
|
|
18
|
+
'proxyReq',
|
|
19
|
+
'proxyReqWs',
|
|
20
|
+
'proxyRes',
|
|
21
|
+
'open',
|
|
22
|
+
'close'
|
|
23
|
+
];
|
|
24
|
+
const handlers = {};
|
|
25
|
+
for (const event of proxyEvents) {
|
|
26
|
+
// all handlers for the http-proxy events are prefixed with 'on'.
|
|
27
|
+
// loop through options and try to find these handlers
|
|
28
|
+
// and add them to the handlers object for subscription in init().
|
|
29
|
+
const eventName = _.camelCase('on ' + event);
|
|
30
|
+
const fnHandler = _.get(options, eventName);
|
|
31
|
+
if (_.isFunction(fnHandler)) {
|
|
32
|
+
handlers[event] = fnHandler;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// add default error handler in absence of error handler
|
|
36
|
+
if (!_.isFunction(handlers.error)) {
|
|
37
|
+
handlers.error = defaultErrorHandler;
|
|
38
|
+
}
|
|
39
|
+
// add default close handler in absence of close handler
|
|
40
|
+
if (!_.isFunction(handlers.close)) {
|
|
41
|
+
handlers.close = logClose;
|
|
42
|
+
}
|
|
43
|
+
return handlers;
|
|
44
|
+
}
|
|
45
|
+
exports.getHandlers = getHandlers;
|
|
46
|
+
function defaultErrorHandler(err, req, res) {
|
|
47
|
+
const host = req.headers && req.headers.host;
|
|
48
|
+
const code = err.code;
|
|
49
|
+
if (res.writeHead && !res.headersSent) {
|
|
50
|
+
if (/HPE_INVALID/.test(code)) {
|
|
51
|
+
res.writeHead(502);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
switch (code) {
|
|
55
|
+
case 'ECONNRESET':
|
|
56
|
+
case 'ENOTFOUND':
|
|
57
|
+
case 'ECONNREFUSED':
|
|
58
|
+
res.writeHead(504);
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
res.writeHead(500);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
res.end('Error occured while trying to proxy to: ' + host + req.url);
|
|
66
|
+
}
|
|
67
|
+
function logClose(req, socket, head) {
|
|
68
|
+
// view disconnected websocket connections
|
|
69
|
+
logger.info('[HPM] Client disconnected');
|
|
70
|
+
}
|