cloudcms-server 0.9.270 → 0.9.271

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.
Files changed (45) hide show
  1. package/middleware/proxy/proxy.js +5 -9
  2. package/package.json +2 -2
  3. package/temp/http-proxy/.auto-changelog +6 -0
  4. package/temp/http-proxy/.gitattributes +1 -0
  5. package/temp/http-proxy/CHANGELOG.md +1872 -0
  6. package/temp/http-proxy/CODE_OF_CONDUCT.md +74 -0
  7. package/temp/http-proxy/LICENSE +23 -0
  8. package/temp/http-proxy/README.md +568 -0
  9. package/temp/http-proxy/codecov.yml +10 -0
  10. package/temp/http-proxy/index.js +13 -0
  11. package/temp/http-proxy/lib/http-proxy/common.js +220 -0
  12. package/temp/http-proxy/lib/http-proxy/index.js +174 -0
  13. package/temp/http-proxy/lib/http-proxy/passes/web-incoming.js +174 -0
  14. package/temp/http-proxy/lib/http-proxy/passes/web-outgoing.js +135 -0
  15. package/temp/http-proxy/lib/http-proxy/passes/ws-incoming.js +141 -0
  16. package/temp/http-proxy/lib/index.js +13 -0
  17. package/temp/http-proxy/package.json +41 -0
  18. package/temp/http-proxy/renovate.json +19 -0
  19. package/temp/node-http-proxy/.eslintignore +3 -0
  20. package/temp/node-http-proxy/.eslintrc.js +21 -0
  21. package/temp/node-http-proxy/.github/workflows/ci.yml +30 -0
  22. package/temp/node-http-proxy/.prettierrc +7 -0
  23. package/temp/node-http-proxy/CODE_OF_CONDUCT.md +74 -0
  24. package/temp/node-http-proxy/LICENSE +23 -0
  25. package/temp/node-http-proxy/README.md +568 -0
  26. package/temp/node-http-proxy/codecov.yml +10 -0
  27. package/temp/node-http-proxy/dist/http-proxy/common.js +220 -0
  28. package/temp/node-http-proxy/dist/http-proxy/index.js +174 -0
  29. package/temp/node-http-proxy/dist/http-proxy/passes/web-incoming.js +174 -0
  30. package/temp/node-http-proxy/dist/http-proxy/passes/web-outgoing.js +135 -0
  31. package/temp/node-http-proxy/dist/http-proxy/passes/ws-incoming.js +141 -0
  32. package/temp/node-http-proxy/dist/index.js +13 -0
  33. package/temp/node-http-proxy/lib/http-proxy/common.js +265 -0
  34. package/temp/node-http-proxy/lib/http-proxy/index.ts +242 -0
  35. package/temp/node-http-proxy/lib/http-proxy/passes/web-incoming.js +208 -0
  36. package/temp/node-http-proxy/lib/http-proxy/passes/web-outgoing.js +163 -0
  37. package/temp/node-http-proxy/lib/http-proxy/passes/ws-incoming.js +179 -0
  38. package/temp/node-http-proxy/lib/index.ts +13 -0
  39. package/temp/node-http-proxy/lib/types.d.ts +277 -0
  40. package/temp/node-http-proxy/package-lock.json +5028 -0
  41. package/temp/node-http-proxy/package.json +47 -0
  42. package/temp/node-http-proxy/tsconfig.build.json +4 -0
  43. package/temp/node-http-proxy/tsconfig.json +115 -0
  44. package/temp/node-http-proxy/vitest.config.ts +9 -0
  45. package/util/proxy-factory.js +39 -128
@@ -0,0 +1,242 @@
1
+ import http, {
2
+ IncomingMessage,
3
+ Server as HttpServer,
4
+ ServerResponse,
5
+ } from 'http';
6
+ import https from 'https';
7
+ import { Duplex } from 'stream';
8
+ import { parse as parse_url } from 'url';
9
+ import EE3 from 'eventemitter3';
10
+ import web from './passes/web-incoming';
11
+ import ws from './passes/ws-incoming';
12
+ import { ServerOptions } from '../types';
13
+
14
+ interface PassInterface {
15
+ (this: ProxyServerNew, req: IncomingMessage, res: ServerResponse):
16
+ | boolean
17
+ | void;
18
+ (this: ProxyServerNew, req: IncomingMessage, res: Duplex, head: Buffer):
19
+ | boolean
20
+ | void;
21
+ (
22
+ this: ProxyServerNew,
23
+ req: IncomingMessage,
24
+ res: ServerResponse,
25
+ options: ServerOptions,
26
+ head: Buffer,
27
+ server: ProxyServerNew,
28
+ errorCallback: (
29
+ err: Error,
30
+ req: IncomingMessage,
31
+ res: ServerResponse,
32
+ url: ServerOptions['target'],
33
+ ) => void,
34
+ ): boolean | void;
35
+ }
36
+
37
+ /**
38
+ * Returns a function that creates the loader for
39
+ * either `ws` or `web`'s passes.
40
+ *
41
+ * Examples:
42
+ *
43
+ * createRightProxy('ws')
44
+ * // => [Function]
45
+ *
46
+ * @param type
47
+ *
48
+ * @return Loader function that when called returns an iterator for the right passes
49
+ *
50
+ * @api private
51
+ */
52
+ function createRightProxy(type: 'web' | 'ws') {
53
+ return function (options: ServerOptions) {
54
+ return function (
55
+ this: ProxyServerNew,
56
+ req: IncomingMessage,
57
+ resOrSocket: ServerResponse | Duplex,
58
+ ): void {
59
+ const passes = type === 'ws' ? this.wsPasses : this.webPasses,
60
+ // TODO: Migrate away from arguments.
61
+ // eslint-disable-next-line prefer-rest-params
62
+ args = [].slice.call(arguments) as any[];
63
+ let cntr = args.length - 1,
64
+ head,
65
+ cbl;
66
+
67
+ /* optional args parse begin */
68
+ if (typeof args[cntr] === 'function') {
69
+ cbl = args[cntr];
70
+
71
+ cntr--;
72
+ }
73
+
74
+ let requestOptions = options;
75
+ if (!(args[cntr] instanceof Buffer) && args[cntr] !== resOrSocket) {
76
+ //Copy global options
77
+ requestOptions = Object.assign({}, options);
78
+ //Overwrite with request options
79
+ Object.assign(requestOptions, args[cntr]);
80
+
81
+ cntr--;
82
+ }
83
+
84
+ if (args[cntr] instanceof Buffer) {
85
+ head = args[cntr];
86
+ }
87
+
88
+ /* optional args parse end */
89
+
90
+ (['target', 'forward'] as const).forEach(function (e) {
91
+ if (typeof requestOptions[e] === 'string')
92
+ requestOptions[e] = parse_url(requestOptions[e] as string);
93
+ });
94
+
95
+ if (!requestOptions.target && !requestOptions.forward) {
96
+ this.emit('error', new Error('Must provide a proper URL as target'));
97
+ return;
98
+ }
99
+
100
+ for (let i = 0; i < passes.length; i++) {
101
+ /**
102
+ * Call of passes functions
103
+ * pass(req, res, options, head)
104
+ *
105
+ * In WebSockets case the `res` variable
106
+ * refer to the connection socket
107
+ * pass(req, socket, options, head)
108
+ */
109
+ // TODO: Figure out the typing here.
110
+ // @ts-ignore
111
+ if (passes[i](req, resOrSocket, requestOptions, head, this, cbl)) {
112
+ // passes can return a truthy value to halt the loop
113
+ break;
114
+ }
115
+ }
116
+ };
117
+ };
118
+ }
119
+
120
+ export class ProxyServerNew extends EE3 {
121
+ options: ServerOptions;
122
+ web: PassInterface;
123
+ ws: PassInterface;
124
+ webPasses: PassInterface[];
125
+ wsPasses: PassInterface[];
126
+
127
+ _server: HttpServer | undefined;
128
+
129
+ constructor(options: ServerOptions) {
130
+ super();
131
+ options = options || {};
132
+ options.prependPath = options.prependPath !== false;
133
+
134
+ this.web = createRightProxy('web')(options);
135
+ this.ws = createRightProxy('ws')(options);
136
+ this.options = options;
137
+
138
+ this.webPasses = Object.keys(web).map(function (pass) {
139
+ // TODO: Figure out the typing here.
140
+ return web[pass as keyof typeof web] as PassInterface;
141
+ });
142
+
143
+ this.wsPasses = Object.keys(ws).map(function (pass) {
144
+ // TODO: Figure out the typing here.
145
+ return ws[pass as keyof typeof ws] as PassInterface;
146
+ });
147
+
148
+ this.on('error', this.onError, this);
149
+ }
150
+
151
+ after(type: 'web' | 'ws', passName: string, callback: PassInterface) {
152
+ const passes = type === 'ws' ? this.wsPasses : this.webPasses;
153
+ let i = -1;
154
+
155
+ passes.forEach((v, idx) => {
156
+ if (v.name === passName) i = idx;
157
+ });
158
+
159
+ if (i === -1) throw new Error('No such pass');
160
+
161
+ passes.splice(i++, 0, callback);
162
+ }
163
+
164
+ before(type: 'web' | 'ws', passName: string, callback: PassInterface) {
165
+ const passes = type === 'ws' ? this.wsPasses : this.webPasses;
166
+ let i = -1;
167
+
168
+ passes.forEach((v, idx) => {
169
+ if (v.name === passName) i = idx;
170
+ });
171
+
172
+ if (i === -1) throw new Error('No such pass');
173
+
174
+ passes.splice(i, 0, callback);
175
+ }
176
+
177
+ close(callback?: () => void) {
178
+ if (this._server) {
179
+ this._server.close(() => {
180
+ this._server = undefined;
181
+ callback?.();
182
+ });
183
+ }
184
+ }
185
+
186
+ listen(port: number, hostname: string) {
187
+ const closure = (req: IncomingMessage, res: ServerResponse) => {
188
+ this.web(req, res);
189
+ };
190
+
191
+ const server = this.options.ssl
192
+ ? https.createServer(this.options.ssl, closure)
193
+ : http.createServer(closure);
194
+
195
+ if (this.options.ws) {
196
+ server.on(
197
+ 'upgrade',
198
+ (req: IncomingMessage, socket: Duplex, head: Buffer) => {
199
+ this.ws(req, socket, head);
200
+ },
201
+ );
202
+ }
203
+
204
+ server.listen(port, hostname);
205
+
206
+ this._server = server;
207
+
208
+ return this;
209
+ }
210
+
211
+ onError(err: Error) {
212
+ //
213
+ // Remark: Replicate node core behavior using EE3
214
+ // so we force people to handle their own errors
215
+ //
216
+ if (super.listeners('error').length === 1) {
217
+ throw err;
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Creates the proxy server.
224
+ *
225
+ * Examples:
226
+ *
227
+ * httpProxy.createServer({ .. }, 8000)
228
+ * // => '{ web: [Function], ws: [Function] ... }'
229
+ *
230
+ * @param options Config object passed to the proxy
231
+ *
232
+ * @return Proxy object with handlers for `ws` and `web` requests
233
+ *
234
+ * @api public
235
+ */
236
+ export function createProxyServer(options: ServerOptions) {
237
+ return new ProxyServerNew(options);
238
+ }
239
+
240
+ export const createProxy = createProxyServer;
241
+
242
+ export const createServer = createProxyServer;
@@ -0,0 +1,208 @@
1
+ const httpNative = require('http'),
2
+ httpsNative = require('https'),
3
+ common = require('../common'),
4
+ followRedirects = require('follow-redirects'),
5
+ web_o = Object.values(require('./web-outgoing'));
6
+
7
+ const nativeAgents = { http: httpNative, https: httpsNative };
8
+
9
+ /*!
10
+ * Array of passes.
11
+ *
12
+ * A `pass` is just a function that is executed on `req, res, options`
13
+ * so that you can easily add new checks while still keeping the base
14
+ * flexible.
15
+ */
16
+
17
+ module.exports = {
18
+ /**
19
+ * Sets `content-length` to '0' if request is of DELETE type.
20
+ *
21
+ * @param {ClientRequest} req Request object
22
+ * @param {IncomingMessage} res Response object
23
+ * @param {object} options Config object passed to the proxy
24
+ *
25
+ * @api private
26
+ */
27
+
28
+ deleteLength: function deleteLength(req, res, options) {
29
+ if (
30
+ (req.method === 'DELETE' || req.method === 'OPTIONS') &&
31
+ !req.headers['content-length']
32
+ ) {
33
+ req.headers['content-length'] = '0';
34
+ delete req.headers['transfer-encoding'];
35
+ }
36
+ },
37
+
38
+ /**
39
+ * Sets timeout in request socket if it was specified in options.
40
+ *
41
+ * @param {ClientRequest} req Request object
42
+ * @param {IncomingMessage} res Response object
43
+ * @param {object} options Config object passed to the proxy
44
+ *
45
+ * @api private
46
+ */
47
+
48
+ timeout: function timeout(req, res, options) {
49
+ if (options.timeout) {
50
+ req.socket.setTimeout(options.timeout);
51
+ }
52
+ },
53
+
54
+ /**
55
+ * Sets `x-forwarded-*` headers if specified in config.
56
+ *
57
+ * @param {ClientRequest} req Request object
58
+ * @param {IncomingMessage} res Response object
59
+ * @param {object} options Config object passed to the proxy
60
+ *
61
+ * @api private
62
+ */
63
+
64
+ XHeaders: function XHeaders(req, res, options) {
65
+ if (!options.xfwd) return;
66
+
67
+ const encrypted = req.isSpdy || common.hasEncryptedConnection(req);
68
+ const values = {
69
+ for: req.connection.remoteAddress || req.socket.remoteAddress,
70
+ port: common.getPort(req),
71
+ proto: encrypted ? 'https' : 'http',
72
+ };
73
+
74
+ ['for', 'port', 'proto'].forEach(function (header) {
75
+ req.headers['x-forwarded-' + header] =
76
+ (req.headers['x-forwarded-' + header] || '') +
77
+ (req.headers['x-forwarded-' + header] ? ',' : '') +
78
+ values[header];
79
+ });
80
+
81
+ req.headers['x-forwarded-host'] =
82
+ req.headers['x-forwarded-host'] || req.headers['host'] || '';
83
+ },
84
+
85
+ /**
86
+ * Does the actual proxying. If `forward` is enabled fires up
87
+ * a ForwardStream, same happens for ProxyStream. The request
88
+ * just dies otherwise.
89
+ *
90
+ * @param {ClientRequest} req Request object
91
+ * @param {IncomingMessage} res Response object
92
+ * @param {object} options Config object passed to the proxy
93
+ *
94
+ * @api private
95
+ */
96
+
97
+ stream: function stream(req, res, options, _, server, clb) {
98
+ // And we begin!
99
+ server.emit('start', req, res, options.target || options.forward);
100
+
101
+ const agents = options.followRedirects ? followRedirects : nativeAgents;
102
+ const http = agents.http;
103
+ const https = agents.https;
104
+
105
+ if (options.forward) {
106
+ // If forward enable, so just pipe the request
107
+ const forwardReq = (
108
+ options.forward.protocol === 'https:' ? https : http
109
+ ).request(
110
+ common.setupOutgoing(options.ssl || {}, options, req, 'forward'),
111
+ );
112
+
113
+ // error handler (e.g. ECONNRESET, ECONNREFUSED)
114
+ // Handle errors on incoming request as well as it makes sense to
115
+ const forwardError = createErrorHandler(forwardReq, options.forward);
116
+ req.on('error', forwardError);
117
+ forwardReq.on('error', forwardError);
118
+
119
+ (options.buffer || req).pipe(forwardReq);
120
+ if (!options.target) {
121
+ return res.end();
122
+ }
123
+ }
124
+
125
+ // Request initalization
126
+ const proxyReq = (
127
+ options.target.protocol === 'https:' ? https : http
128
+ ).request(common.setupOutgoing(options.ssl || {}, options, req));
129
+
130
+ // Enable developers to modify the proxyReq before headers are sent
131
+ proxyReq.on('socket', function (socket) {
132
+ if (server && !proxyReq.getHeader('expect')) {
133
+ server.emit('proxyReq', proxyReq, req, res, options);
134
+ }
135
+ });
136
+
137
+ // allow outgoing socket to timeout so that we could
138
+ // show an error page at the initial request
139
+ if (options.proxyTimeout) {
140
+ proxyReq.setTimeout(options.proxyTimeout, function () {
141
+ proxyReq.destroy();
142
+ });
143
+ }
144
+
145
+ // Ensure we abort proxy if request is aborted
146
+ // Need to use different methods due to node changes in 15.0.0.
147
+
148
+ // In node < 15.0.0, listen for request abort and destroy the proxy request.
149
+ req.on('aborted', function () {
150
+ proxyReq.destroy();
151
+ });
152
+ // In node > 15.0.0, listen for the close event on the response. If it was
153
+ // destroyed then destroy the proxy request.
154
+ res.on('close', function () {
155
+ if (res.destroyed) {
156
+ proxyReq.destroy();
157
+ }
158
+ });
159
+
160
+ // handle errors in proxy and incoming request, just like for forward proxy
161
+ const proxyError = createErrorHandler(proxyReq, options.target);
162
+ req.on('error', proxyError);
163
+ proxyReq.on('error', proxyError);
164
+
165
+ function createErrorHandler(proxyReq, url) {
166
+ return function proxyError(err) {
167
+ if (req.socket.destroyed && err.code === 'ECONNRESET') {
168
+ server.emit('econnreset', err, req, res, url);
169
+ proxyReq.destroy();
170
+ return;
171
+ }
172
+
173
+ if (clb) {
174
+ clb(err, req, res, url);
175
+ } else {
176
+ server.emit('error', err, req, res, url);
177
+ }
178
+ };
179
+ }
180
+
181
+ (options.buffer || req).pipe(proxyReq);
182
+
183
+ proxyReq.on('response', function (proxyRes) {
184
+ if (server) {
185
+ server.emit('proxyRes', proxyRes, req, res);
186
+ }
187
+
188
+ if (!res.headersSent && !options.selfHandleResponse) {
189
+ for (let i = 0; i < web_o.length; i++) {
190
+ if (web_o[i](req, res, proxyRes, options)) {
191
+ break;
192
+ }
193
+ }
194
+ }
195
+
196
+ if (!res.finished) {
197
+ // Allow us to listen when the proxy has completed
198
+ proxyRes.on('end', function () {
199
+ if (server) server.emit('end', req, res, proxyRes);
200
+ });
201
+ // We pipe to the response unless its expected to be handled by the user
202
+ if (!options.selfHandleResponse) proxyRes.pipe(res);
203
+ } else {
204
+ if (server) server.emit('end', req, res, proxyRes);
205
+ }
206
+ });
207
+ },
208
+ };
@@ -0,0 +1,163 @@
1
+ const url = require('url'),
2
+ common = require('../common');
3
+
4
+ const redirectRegex = /^201|30(1|2|7|8)$/;
5
+
6
+ /*!
7
+ * Array of passes.
8
+ *
9
+ * A `pass` is just a function that is executed on `req, res, options`
10
+ * so that you can easily add new checks while still keeping the base
11
+ * flexible.
12
+ */
13
+
14
+ module.exports = {
15
+ // <--
16
+
17
+ /**
18
+ * If is a HTTP 1.0 request, remove chunk headers
19
+ *
20
+ * @param {ClientRequest} req Request object
21
+ * @param {IncomingMessage} res Response object
22
+ * @param {proxyResponse} proxyRes Response object from the proxy request
23
+ *
24
+ * @api private
25
+ */
26
+ removeChunked: function removeChunked(req, res, proxyRes) {
27
+ if (req.httpVersion === '1.0') {
28
+ delete proxyRes.headers['transfer-encoding'];
29
+ }
30
+ },
31
+
32
+ /**
33
+ * If is a HTTP 1.0 request, set the correct connection header
34
+ * or if connection header not present, then use `keep-alive`
35
+ *
36
+ * @param {ClientRequest} req Request object
37
+ * @param {IncomingMessage} res Response object
38
+ * @param {proxyResponse} proxyRes Response object from the proxy request
39
+ *
40
+ * @api private
41
+ */
42
+ setConnection: function setConnection(req, res, proxyRes) {
43
+ if (req.httpVersion === '1.0') {
44
+ proxyRes.headers.connection = req.headers.connection || 'close';
45
+ } else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) {
46
+ proxyRes.headers.connection = req.headers.connection || 'keep-alive';
47
+ }
48
+ },
49
+
50
+ setRedirectHostRewrite: function setRedirectHostRewrite(
51
+ req,
52
+ res,
53
+ proxyRes,
54
+ options,
55
+ ) {
56
+ if (
57
+ (options.hostRewrite || options.autoRewrite || options.protocolRewrite) &&
58
+ proxyRes.headers['location'] &&
59
+ redirectRegex.test(proxyRes.statusCode)
60
+ ) {
61
+ const target = url.parse(options.target);
62
+ const u = url.parse(proxyRes.headers['location']);
63
+
64
+ // make sure the redirected host matches the target host before rewriting
65
+ if (target.host != u.host) {
66
+ return;
67
+ }
68
+
69
+ if (options.hostRewrite) {
70
+ u.host = options.hostRewrite;
71
+ } else if (options.autoRewrite) {
72
+ u.host = req.headers['host'];
73
+ }
74
+ if (options.protocolRewrite) {
75
+ u.protocol = options.protocolRewrite;
76
+ }
77
+
78
+ proxyRes.headers['location'] = u.format();
79
+ }
80
+ },
81
+ /**
82
+ * Copy headers from proxyResponse to response
83
+ * set each header in response object.
84
+ *
85
+ * @param {ClientRequest} req Request object
86
+ * @param {IncomingMessage} res Response object
87
+ * @param {proxyResponse} proxyRes Response object from the proxy request
88
+ * @param {Object} options options.cookieDomainRewrite: Config to rewrite cookie domain
89
+ *
90
+ * @api private
91
+ */
92
+ writeHeaders: function writeHeaders(req, res, proxyRes, options) {
93
+ let rewriteCookieDomainConfig = options.cookieDomainRewrite,
94
+ rewriteCookiePathConfig = options.cookiePathRewrite,
95
+ rawHeaderKeyMap;
96
+ const preserveHeaderKeyCase = options.preserveHeaderKeyCase,
97
+ setHeader = function (key, header) {
98
+ if (header == undefined) return;
99
+ if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') {
100
+ header = common.rewriteCookieProperty(
101
+ header,
102
+ rewriteCookieDomainConfig,
103
+ 'domain',
104
+ );
105
+ }
106
+ if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') {
107
+ header = common.rewriteCookieProperty(
108
+ header,
109
+ rewriteCookiePathConfig,
110
+ 'path',
111
+ );
112
+ }
113
+ res.setHeader(String(key).trim(), header);
114
+ };
115
+
116
+ if (typeof rewriteCookieDomainConfig === 'string') {
117
+ //also test for ''
118
+ rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig };
119
+ }
120
+
121
+ if (typeof rewriteCookiePathConfig === 'string') {
122
+ //also test for ''
123
+ rewriteCookiePathConfig = { '*': rewriteCookiePathConfig };
124
+ }
125
+
126
+ // message.rawHeaders is added in: v0.11.6
127
+ // https://nodejs.org/api/http.html#http_message_rawheaders
128
+ if (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) {
129
+ rawHeaderKeyMap = {};
130
+ for (let i = 0; i < proxyRes.rawHeaders.length; i += 2) {
131
+ const key = proxyRes.rawHeaders[i];
132
+ rawHeaderKeyMap[key.toLowerCase()] = key;
133
+ }
134
+ }
135
+
136
+ Object.keys(proxyRes.headers).forEach(function (key) {
137
+ const header = proxyRes.headers[key];
138
+ if (preserveHeaderKeyCase && rawHeaderKeyMap) {
139
+ key = rawHeaderKeyMap[key] || key;
140
+ }
141
+ setHeader(key, header);
142
+ });
143
+ },
144
+
145
+ /**
146
+ * Set the statusCode from the proxyResponse
147
+ *
148
+ * @param {ClientRequest} req Request object
149
+ * @param {IncomingMessage} res Response object
150
+ * @param {proxyResponse} proxyRes Response object from the proxy request
151
+ *
152
+ * @api private
153
+ */
154
+ writeStatusCode: function writeStatusCode(req, res, proxyRes) {
155
+ // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers])
156
+ if (proxyRes.statusMessage) {
157
+ res.statusCode = proxyRes.statusCode;
158
+ res.statusMessage = proxyRes.statusMessage;
159
+ } else {
160
+ res.statusCode = proxyRes.statusCode;
161
+ }
162
+ },
163
+ };