http-proxy-middleware 0.17.2-beta → 0.18.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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.18.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.18.0)
4
+ - fix(vulnerability): update micromatch to v3.x ([npm:braces:20180219](https://snyk.io/test/npm/http-proxy-middleware?tab=issues&severity=high&severity=medium&severity=low#npm:braces:20180219
5
+ ))
6
+ - test(node): drop node 0.x support ([#212](https://github.com/chimurai/http-proxy-middleware/pull/212))
7
+
8
+
9
+ ## [v0.17.4](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.4)
10
+ - fix(ntlm authentication): fixed bug preventing proxying with ntlm authentication. ([#132](https://github.com/chimurai/http-proxy-middleware/pull/149)) (Thanks: [EladBezalel](https://github.com/EladBezalel), [oshri551](https://github.com/oshri551))
11
+
12
+
13
+ ## [v0.17.3](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.3)
14
+ - fix(onError): improve default proxy error handling. http status codes (504, 502 and 500). ([#132](https://github.com/chimurai/http-proxy-middleware/pull/132)) ([graingert](https://github.com/graingert))
15
+
16
+ ## [v0.17.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.2)
17
+ - feat(logging): improve error message & add link to Node errors page. ([#106](https://github.com/chimurai/http-proxy-middleware/pull/106)) ([cloudmu](https://github.com/cloudmu))
18
+ - feat(pathRewrite): path can be empty string. ([#110](https://github.com/chimurai/http-proxy-middleware/pull/110)) ([sunnylqm](https://github.com/sunnylqm))
19
+ - bug(websocket): memory leak when option 'ws:true' is used. ([#114](https://github.com/chimurai/http-proxy-middleware/pull/114)) ([julbra](https://github.com/julbra))
20
+ - chore(package.json): reduce package size. ([#109](https://github.com/chimurai/http-proxy-middleware/pull/109))
21
+
3
22
  ## [v0.17.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.1)
4
23
  - fix(Express sub Router): 404 on non-proxy routes ([#94](https://github.com/chimurai/http-proxy-middleware/issues/94))
5
24
 
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![Coveralls](https://img.shields.io/coveralls/chimurai/http-proxy-middleware.svg?style=flat-square)](https://coveralls.io/r/chimurai/http-proxy-middleware)
5
5
  [![dependency Status](https://img.shields.io/david/chimurai/http-proxy-middleware.svg?style=flat-square)](https://david-dm.org/chimurai/http-proxy-middleware#info=dependencies)
6
6
  [![dependency Status](https://snyk.io/test/npm/http-proxy-middleware/badge.svg)](https://snyk.io/test/npm/http-proxy-middleware)
7
+ [![JavaScript Style Guide](https://img.shields.io/badge/codestyle-standard-brightgreen.svg)](https://standardjs.com)
7
8
 
8
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).
9
10
 
@@ -31,7 +32,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
31
32
 
32
33
  ## Table of Contents
33
34
 
34
- <!-- MarkdownTOC autolink=true bracket=round depth=3 -->
35
+ <!-- MarkdownTOC autolink=true bracket=round depth=2 -->
35
36
 
36
37
  - [Install](#install)
37
38
  - [Core concept](#core-concept)
@@ -107,8 +108,8 @@ var options = {
107
108
  changeOrigin: true, // needed for virtual hosted sites
108
109
  ws: true, // proxy websockets
109
110
  pathRewrite: {
110
- '^/old/api' : '/new/api', // rewrite path
111
- '^/remove/api' : '/api' // remove path
111
+ '^/api/old-path' : '/api/new-path', // rewrite path
112
+ '^/api/remove/path' : '/path' // remove base path
112
113
  },
113
114
  router: {
114
115
  // when request.headers.host == 'dev.localhost:3000',
@@ -130,7 +131,7 @@ var app = express();
130
131
 
131
132
  Providing an alternative way to decide which requests should be proxied; In case you are not able to use the server's [`path` parameter](http://expressjs.com/en/4x/api.html#app.use) to mount the proxy or when you need more flexibility.
132
133
 
133
- The [RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is be used for context matching.
134
+ [RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used for context matching.
134
135
 
135
136
  ```
136
137
  foo://example.com:8042/over/there?name=ferret#nose
@@ -304,15 +305,29 @@ The following options are provided by the underlying [http-proxy](https://github
304
305
  * **option.xfwd**: true/false, adds x-forward headers
305
306
  * **option.secure**: true/false, if you want to verify the SSL Certs
306
307
  * **option.toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies)
307
- * **option.prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path>
308
- * **option.ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request>
308
+ * **option.prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
309
+ * **option.ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
309
310
  * **option.localAddress** : Local interface string to bind for outgoing connections
310
- * **option.changeOrigin**: true/false, adds host to request header.
311
+ * **option.changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL
311
312
  * **option.auth** : Basic authentication i.e. 'user:password' to compute an Authorization header.
312
313
  * **option.hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects.
313
314
  * **option.autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
314
315
  * **option.protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
316
+ * **option.cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values:
317
+ * `false` (default): disable cookie rewriting
318
+ * String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`.
319
+ * Object: mapping of domains to new domains, use `"*"` to match all domains.
320
+ For example keep one domain unchanged, rewrite one domain and remove other domains:
321
+ ```
322
+ cookieDomainRewrite: {
323
+ "unchanged.domain": "unchanged.domain",
324
+ "old.domain": "new.domain",
325
+ "*": ""
326
+ }
327
+ ```
315
328
  * **option.headers**: object, adds [request headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields). (Example: `{host:'www.example.org'}`)
329
+ * **option.proxyTimeout**: timeout (in millis) when proxy receives no response from target
330
+
316
331
 
317
332
 
318
333
  ## Shorthand
@@ -405,18 +420,13 @@ Run the test suite:
405
420
  ```bash
406
421
  # install dependencies
407
422
  $ npm install
408
- ```
409
423
 
410
- unit testing
424
+ # linting
425
+ $ npm run lint
411
426
 
412
- ```bash
413
427
  # unit tests
414
428
  $ npm test
415
- ```
416
-
417
- coverage
418
429
 
419
- ```bash
420
430
  # code coverage
421
431
  $ npm run cover
422
432
  ```
@@ -430,4 +440,4 @@ $ npm run cover
430
440
 
431
441
  The MIT License (MIT)
432
442
 
433
- Copyright (c) 2015-2016 Steven Chim
443
+ Copyright (c) 2015-2017 Steven Chim
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
- var HPM = require('./lib');
1
+ var HPM = require('./lib')
2
2
 
3
- module.exports = function(context, opts) {
4
- return new HPM(context, opts);
5
- };
3
+ module.exports = function (context, opts) {
4
+ return new HPM(context, opts)
5
+ }
@@ -1,54 +1,55 @@
1
- var _ = require('lodash');
2
- var url = require('url');
3
- var logger = require('./logger').getInstance();
1
+ var _ = require('lodash')
2
+ var url = require('url')
3
+ var ERRORS = require('./errors')
4
+ var logger = require('./logger').getInstance()
4
5
 
5
6
  module.exports = {
6
- createConfig: createConfig
7
- };
8
-
9
- function createConfig(context, opts) {
10
- // structure of config object to be returned
11
- var config = {
12
- context: undefined,
13
- options: {}
14
- };
15
-
16
- // app.use('/api', proxy({target:'http://localhost:9000'}));
17
- if (isContextless(context, opts)) {
18
- config.context = '/';
19
- config.options = _.assign(config.options, context);
20
- }
21
- // app.use('/api', proxy('http://localhost:9000'));
22
- // app.use(proxy('http://localhost:9000/api'));
23
- else if (isStringShortHand(context)) {
24
- var oUrl = url.parse(context);
25
- var target = [oUrl.protocol, '//', oUrl.host].join('');
26
-
27
- config.context = oUrl.pathname || '/';
28
- config.options = _.assign(config.options, {target: target}, opts);
29
-
30
- if (oUrl.protocol === 'ws:' || oUrl.protocol === 'wss:') {
31
- config.options.ws = true;
32
- }
33
- // app.use('/api', proxy({target:'http://localhost:9000'}));
34
- } else {
35
- config.context = context;
36
- config.options = _.assign(config.options, opts);
7
+ createConfig: createConfig
8
+ }
9
+
10
+ function createConfig (context, opts) {
11
+ // structure of config object to be returned
12
+ var config = {
13
+ context: undefined,
14
+ options: {}
15
+ }
16
+
17
+ // app.use('/api', proxy({target:'http://localhost:9000'}));
18
+ if (isContextless(context, opts)) {
19
+ config.context = '/'
20
+ config.options = _.assign(config.options, context)
21
+
22
+ // app.use('/api', proxy('http://localhost:9000'));
23
+ // app.use(proxy('http://localhost:9000/api'));
24
+ } else if (isStringShortHand(context)) {
25
+ var oUrl = url.parse(context)
26
+ var target = [oUrl.protocol, '//', oUrl.host].join('')
27
+
28
+ config.context = oUrl.pathname || '/'
29
+ config.options = _.assign(config.options, {target: target}, opts)
30
+
31
+ if (oUrl.protocol === 'ws:' || oUrl.protocol === 'wss:') {
32
+ config.options.ws = true
37
33
  }
34
+ // app.use('/api', proxy({target:'http://localhost:9000'}));
35
+ } else {
36
+ config.context = context
37
+ config.options = _.assign(config.options, opts)
38
+ }
38
39
 
39
- configureLogger(config.options);
40
+ configureLogger(config.options)
40
41
 
41
- if (!config.options.target) {
42
- throw new Error('[HPM] Missing "target" option. Example: {target: "http://www.example.org"}');
43
- }
42
+ if (!config.options.target) {
43
+ throw new Error(ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING)
44
+ }
44
45
 
45
- // Legacy option.proxyHost
46
- config.options = mapLegacyProxyHostOption(config.options);
46
+ // Legacy option.proxyHost
47
+ config.options = mapLegacyProxyHostOption(config.options)
47
48
 
48
- // Legacy option.proxyTable > option.router
49
- config.options = mapLegacyProxyTableOption(config.options);
49
+ // Legacy option.proxyTable > option.router
50
+ config.options = mapLegacyProxyTableOption(config.options)
50
51
 
51
- return config;
52
+ return config
52
53
  }
53
54
 
54
55
  /**
@@ -62,10 +63,10 @@ function createConfig(context, opts) {
62
63
  * @param {String} context [description]
63
64
  * @return {Boolean} [description]
64
65
  */
65
- function isStringShortHand(context) {
66
- if (_.isString(context)) {
67
- return (url.parse(context).host) ? true : false;
68
- }
66
+ function isStringShortHand (context) {
67
+ if (_.isString(context)) {
68
+ return !!(url.parse(context).host)
69
+ }
69
70
  }
70
71
 
71
72
  /**
@@ -79,48 +80,48 @@ function isStringShortHand(context) {
79
80
  * @param {*} opts [description]
80
81
  * @return {Boolean} [description]
81
82
  */
82
- function isContextless(context, opts) {
83
- return (_.isPlainObject(context) && _.isEmpty(opts));
83
+ function isContextless (context, opts) {
84
+ return (_.isPlainObject(context) && _.isEmpty(opts))
84
85
  }
85
86
 
86
- function mapLegacyProxyHostOption(options) {
87
- // set options.headers.host when option.proxyHost is provided
88
- if (options.proxyHost) {
89
- logger.warn('*************************************');
90
- logger.warn('[HPM] Deprecated "option.proxyHost"');
91
- logger.warn(' Use "option.changeOrigin" or "option.headers.host" instead');
92
- logger.warn(' "option.proxyHost" will be removed in future release.');
93
- logger.warn('*************************************');
94
-
95
- options.headers = options.headers || {};
96
- options.headers.host = options.proxyHost;
97
- }
87
+ function mapLegacyProxyHostOption (options) {
88
+ // set options.headers.host when option.proxyHost is provided
89
+ if (options.proxyHost) {
90
+ logger.warn('*************************************')
91
+ logger.warn('[HPM] Deprecated "option.proxyHost"')
92
+ logger.warn(' Use "option.changeOrigin" or "option.headers.host" instead')
93
+ logger.warn(' "option.proxyHost" will be removed in future release.')
94
+ logger.warn('*************************************')
98
95
 
99
- return options;
96
+ options.headers = options.headers || {}
97
+ options.headers.host = options.proxyHost
98
+ }
99
+
100
+ return options
100
101
  }
101
102
 
102
103
  // Warn deprecated proxyTable api usage
103
- function mapLegacyProxyTableOption(options) {
104
- if (options.proxyTable) {
105
- logger.warn('*************************************');
106
- logger.warn('[HPM] Deprecated "option.proxyTable"');
107
- logger.warn(' Use "option.router" instead');
108
- logger.warn(' "option.proxyTable" will be removed in future release.');
109
- logger.warn('*************************************');
110
-
111
- options.router = _.clone(options.proxyTable);
112
- _.omit(options, 'proxyTable');
113
- }
114
-
115
- return options;
104
+ function mapLegacyProxyTableOption (options) {
105
+ if (options.proxyTable) {
106
+ logger.warn('*************************************')
107
+ logger.warn('[HPM] Deprecated "option.proxyTable"')
108
+ logger.warn(' Use "option.router" instead')
109
+ logger.warn(' "option.proxyTable" will be removed in future release.')
110
+ logger.warn('*************************************')
111
+
112
+ options.router = _.clone(options.proxyTable)
113
+ _.omit(options, 'proxyTable')
114
+ }
115
+
116
+ return options
116
117
  }
117
118
 
118
- function configureLogger(options) {
119
- if (options.logLevel) {
120
- logger.setLevel(options.logLevel);
121
- }
119
+ function configureLogger (options) {
120
+ if (options.logLevel) {
121
+ logger.setLevel(options.logLevel)
122
+ }
122
123
 
123
- if (options.logProvider) {
124
- logger.setProvider(options.logProvider);
125
- }
124
+ if (options.logProvider) {
125
+ logger.setProvider(options.logProvider)
126
+ }
126
127
  }
@@ -1,43 +1,43 @@
1
- var _ = require('lodash');
2
- var url = require('url');
3
- var isGlob = require('is-glob');
4
- var micromatch = require('micromatch');
1
+ var _ = require('lodash')
2
+ var url = require('url')
3
+ var isGlob = require('is-glob')
4
+ var micromatch = require('micromatch')
5
+ var ERRORS = require('./errors')
5
6
 
6
7
  module.exports = {
7
- match: matchContext
8
- };
8
+ match: matchContext
9
+ }
9
10
 
10
- function matchContext(context, uri, req) {
11
+ function matchContext (context, uri, req) {
12
+ // single path
13
+ if (isStringPath(context)) {
14
+ return matchSingleStringPath(context, uri)
15
+ }
11
16
 
12
- // single path
13
- if (isStringPath(context)) {
14
- return matchSingleStringPath(context, uri);
15
- }
17
+ // single glob path
18
+ if (isGlobPath(context)) {
19
+ return matchSingleGlobPath(context, uri)
20
+ }
16
21
 
17
- // single glob path
18
- if (isGlobPath(context)) {
19
- return matchSingleGlobPath(context, uri);
22
+ // multi path
23
+ if (Array.isArray(context)) {
24
+ if (context.every(isStringPath)) {
25
+ return matchMultiPath(context, uri)
20
26
  }
21
-
22
- // multi path
23
- if (Array.isArray(context)) {
24
- if (context.every(isStringPath)) {
25
- return matchMultiPath(context, uri);
26
- }
27
- if (context.every(isGlobPath)) {
28
- return matchMultiGlobPath(context, uri);
29
- }
30
-
31
- throw new Error('[HPM] Invalid context. Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"]');
27
+ if (context.every(isGlobPath)) {
28
+ return matchMultiGlobPath(context, uri)
32
29
  }
33
30
 
34
- // custom matching
35
- if (_.isFunction(context)) {
36
- var pathname = getUrlPathName(uri);
37
- return context(pathname, req);
38
- }
31
+ throw new Error(ERRORS.ERR_CONTEXT_MATCHER_INVALID_ARRAY)
32
+ }
33
+
34
+ // custom matching
35
+ if (_.isFunction(context)) {
36
+ var pathname = getUrlPathName(uri)
37
+ return context(pathname, req)
38
+ }
39
39
 
40
- throw new Error('[HPM] Invalid context. Expecting something like: "/api" or ["/api", "/ajax"]');
40
+ throw new Error(ERRORS.ERR_CONTEXT_MATCHER_GENERIC)
41
41
  }
42
42
 
43
43
  /**
@@ -45,34 +45,34 @@ function matchContext(context, uri, req) {
45
45
  * @param {String} uri 'http://example.org/api/b/c/d.html'
46
46
  * @return {Boolean}
47
47
  */
48
- function matchSingleStringPath(context, uri) {
49
- var pathname = getUrlPathName(uri);
50
- return pathname.indexOf(context) === 0;
48
+ function matchSingleStringPath (context, uri) {
49
+ var pathname = getUrlPathName(uri)
50
+ return pathname.indexOf(context) === 0
51
51
  }
52
52
 
53
- function matchSingleGlobPath(pattern, uri) {
54
- var pathname = getUrlPathName(uri);
55
- var matches = micromatch(pathname, pattern);
56
- return matches && (matches.length > 0);
53
+ function matchSingleGlobPath (pattern, uri) {
54
+ var pathname = getUrlPathName(uri)
55
+ var matches = micromatch(pathname, pattern)
56
+ return matches && (matches.length > 0)
57
57
  }
58
58
 
59
- function matchMultiGlobPath(patternList, uri) {
60
- return matchSingleGlobPath(patternList, uri);
59
+ function matchMultiGlobPath (patternList, uri) {
60
+ return matchSingleGlobPath(patternList, uri)
61
61
  }
62
62
 
63
63
  /**
64
- * @param {String} context ['/api', '/ajax']
64
+ * @param {String} contextList ['/api', '/ajax']
65
65
  * @param {String} uri 'http://example.org/api/b/c/d.html'
66
66
  * @return {Boolean}
67
67
  */
68
- function matchMultiPath(contextList, uri) {
69
- for (var i = 0; i < contextList.length; i++) {
70
- var context = contextList[i];
71
- if (matchSingleStringPath(context, uri)) {
72
- return true;
73
- }
68
+ function matchMultiPath (contextList, uri) {
69
+ for (var i = 0; i < contextList.length; i++) {
70
+ var context = contextList[i]
71
+ if (matchSingleStringPath(context, uri)) {
72
+ return true
74
73
  }
75
- return false;
74
+ }
75
+ return false
76
76
  }
77
77
 
78
78
  /**
@@ -81,14 +81,14 @@ function matchMultiPath(contextList, uri) {
81
81
  * @param {String} uri from req.url
82
82
  * @return {String} RFC 3986 path
83
83
  */
84
- function getUrlPathName(uri) {
85
- return uri && url.parse(uri).pathname;
84
+ function getUrlPathName (uri) {
85
+ return uri && url.parse(uri).pathname
86
86
  }
87
87
 
88
- function isStringPath(context) {
89
- return _.isString(context) && !isGlob(context);
88
+ function isStringPath (context) {
89
+ return _.isString(context) && !isGlob(context)
90
90
  }
91
91
 
92
- function isGlobPath(context) {
93
- return isGlob(context);
92
+ function isGlobPath (context) {
93
+ return isGlob(context)
94
94
  }
package/lib/errors.js ADDED
@@ -0,0 +1,8 @@
1
+ /* eslint-disable max-len */
2
+
3
+ module.exports = {
4
+ ERR_CONFIG_FACTORY_TARGET_MISSING: '[HPM] Missing "target" option. Example: {target: "http://www.example.org"}',
5
+ ERR_CONTEXT_MATCHER_GENERIC: '[HPM] Invalid context. Expecting something like: "/api" or ["/api", "/ajax"]',
6
+ ERR_CONTEXT_MATCHER_INVALID_ARRAY: '[HPM] Invalid context. Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"]',
7
+ ERR_PATH_REWRITER_CONFIG: '[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function'
8
+ }
package/lib/handlers.js CHANGED
@@ -1,62 +1,74 @@
1
- var _ = require('lodash');
2
- var logger = require('./logger').getInstance();
1
+ var _ = require('lodash')
2
+ var logger = require('./logger').getInstance()
3
3
 
4
4
  module.exports = {
5
- init: init,
6
- getHandlers: getProxyEventHandlers
7
- };
5
+ init: init,
6
+ getHandlers: getProxyEventHandlers
7
+ }
8
8
 
9
- function init(proxy, opts) {
10
- var handlers = getProxyEventHandlers(opts);
9
+ function init (proxy, opts) {
10
+ var handlers = getProxyEventHandlers(opts)
11
11
 
12
- _.forIn(handlers, function(handler, eventName) {
13
- proxy.on(eventName, handlers[eventName]);
14
- });
12
+ _.forIn(handlers, function (handler, eventName) {
13
+ proxy.on(eventName, handlers[eventName])
14
+ })
15
15
 
16
- logger.debug('[HPM] Subscribed to http-proxy events: ', _.keys(handlers));
16
+ logger.debug('[HPM] Subscribed to http-proxy events: ', _.keys(handlers))
17
17
  }
18
18
 
19
- function getProxyEventHandlers(opts) {
20
- // https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events
21
- var proxyEvents = ['error', 'proxyReq', 'proxyReqWs', 'proxyRes', 'open', 'close'];
22
- var handlers = {};
23
-
24
- _.forEach(proxyEvents, function(event) {
25
- // all handlers for the http-proxy events are prefixed with 'on'.
26
- // loop through options and try to find these handlers
27
- // and add them to the handlers object for subscription in init().
28
- var eventName = _.camelCase('on ' + event);
29
- var fnHandler = _.get(opts, eventName);
30
-
31
- if (_.isFunction(fnHandler)) {
32
- handlers[event] = fnHandler;
33
- }
34
- });
35
-
36
- // add default error handler in absence of error handler
37
- if (!_.isFunction(handlers.error)) {
38
- handlers.error = defaultErrorHandler;
39
- }
19
+ function getProxyEventHandlers (opts) {
20
+ // https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events
21
+ var proxyEvents = ['error', 'proxyReq', 'proxyReqWs', 'proxyRes', 'open', 'close']
22
+ var handlers = {}
23
+
24
+ _.forEach(proxyEvents, function (event) {
25
+ // all handlers for the http-proxy events are prefixed with 'on'.
26
+ // loop through options and try to find these handlers
27
+ // and add them to the handlers object for subscription in init().
28
+ var eventName = _.camelCase('on ' + event)
29
+ var fnHandler = _.get(opts, eventName)
40
30
 
41
- // add default close handler in absence of close handler
42
- if (!_.isFunction(handlers.close)) {
43
- handlers.close = logClose;
31
+ if (_.isFunction(fnHandler)) {
32
+ handlers[event] = fnHandler
44
33
  }
34
+ })
45
35
 
46
- return handlers;
47
- };
36
+ // add default error handler in absence of error handler
37
+ if (!_.isFunction(handlers.error)) {
38
+ handlers.error = defaultErrorHandler
39
+ }
40
+
41
+ // add default close handler in absence of close handler
42
+ if (!_.isFunction(handlers.close)) {
43
+ handlers.close = logClose
44
+ }
45
+
46
+ return handlers
47
+ }
48
48
 
49
- function defaultErrorHandler(err, req, res) {
50
- var host = (req.headers && req.headers.host);
49
+ function defaultErrorHandler (err, req, res) {
50
+ var host = (req.headers && req.headers.host)
51
+ var code = err.code
51
52
 
52
- if (res.writeHead && !res.headersSent) {
53
- res.writeHead(500);
53
+ if (res.writeHead && !res.headersSent) {
54
+ if (/HPE_INVALID/.test(code)) {
55
+ res.writeHead(502)
56
+ } else {
57
+ switch (code) {
58
+ case 'ECONNRESET':
59
+ case 'ENOTFOUND':
60
+ case 'ECONNREFUSED':
61
+ res.writeHead(504)
62
+ break
63
+ default: res.writeHead(500)
64
+ }
54
65
  }
66
+ }
55
67
 
56
- res.end('Error occured while trying to proxy to: ' + host + req.url);
68
+ res.end('Error occured while trying to proxy to: ' + host + req.url)
57
69
  }
58
70
 
59
- function logClose(req, socket, head) {
60
- // view disconnected websocket connections
61
- logger.info('[HPM] Client disconnected');
71
+ function logClose (req, socket, head) {
72
+ // view disconnected websocket connections
73
+ logger.info('[HPM] Client disconnected')
62
74
  }