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,135 @@
1
+ "use strict";
2
+ const url = require('url'), common = require('../common');
3
+ const redirectRegex = /^201|30(1|2|7|8)$/;
4
+ /*!
5
+ * Array of passes.
6
+ *
7
+ * A `pass` is just a function that is executed on `req, res, options`
8
+ * so that you can easily add new checks while still keeping the base
9
+ * flexible.
10
+ */
11
+ module.exports = {
12
+ // <--
13
+ /**
14
+ * If is a HTTP 1.0 request, remove chunk headers
15
+ *
16
+ * @param {ClientRequest} req Request object
17
+ * @param {IncomingMessage} res Response object
18
+ * @param {proxyResponse} proxyRes Response object from the proxy request
19
+ *
20
+ * @api private
21
+ */
22
+ removeChunked: function removeChunked(req, res, proxyRes) {
23
+ if (req.httpVersion === '1.0') {
24
+ delete proxyRes.headers['transfer-encoding'];
25
+ }
26
+ },
27
+ /**
28
+ * If is a HTTP 1.0 request, set the correct connection header
29
+ * or if connection header not present, then use `keep-alive`
30
+ *
31
+ * @param {ClientRequest} req Request object
32
+ * @param {IncomingMessage} res Response object
33
+ * @param {proxyResponse} proxyRes Response object from the proxy request
34
+ *
35
+ * @api private
36
+ */
37
+ setConnection: function setConnection(req, res, proxyRes) {
38
+ if (req.httpVersion === '1.0') {
39
+ proxyRes.headers.connection = req.headers.connection || 'close';
40
+ }
41
+ else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) {
42
+ proxyRes.headers.connection = req.headers.connection || 'keep-alive';
43
+ }
44
+ },
45
+ setRedirectHostRewrite: function setRedirectHostRewrite(req, res, proxyRes, options) {
46
+ if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) &&
47
+ proxyRes.headers['location'] &&
48
+ redirectRegex.test(proxyRes.statusCode)) {
49
+ const target = url.parse(options.target);
50
+ const u = url.parse(proxyRes.headers['location']);
51
+ // make sure the redirected host matches the target host before rewriting
52
+ if (target.host != u.host) {
53
+ return;
54
+ }
55
+ if (options.hostRewrite) {
56
+ u.host = options.hostRewrite;
57
+ }
58
+ else if (options.autoRewrite) {
59
+ u.host = req.headers['host'];
60
+ }
61
+ if (options.protocolRewrite) {
62
+ u.protocol = options.protocolRewrite;
63
+ }
64
+ proxyRes.headers['location'] = u.format();
65
+ }
66
+ },
67
+ /**
68
+ * Copy headers from proxyResponse to response
69
+ * set each header in response object.
70
+ *
71
+ * @param {ClientRequest} req Request object
72
+ * @param {IncomingMessage} res Response object
73
+ * @param {proxyResponse} proxyRes Response object from the proxy request
74
+ * @param {Object} options options.cookieDomainRewrite: Config to rewrite cookie domain
75
+ *
76
+ * @api private
77
+ */
78
+ writeHeaders: function writeHeaders(req, res, proxyRes, options) {
79
+ let rewriteCookieDomainConfig = options.cookieDomainRewrite, rewriteCookiePathConfig = options.cookiePathRewrite, rawHeaderKeyMap;
80
+ const preserveHeaderKeyCase = options.preserveHeaderKeyCase, setHeader = function (key, header) {
81
+ if (header == undefined)
82
+ return;
83
+ if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') {
84
+ header = common.rewriteCookieProperty(header, rewriteCookieDomainConfig, 'domain');
85
+ }
86
+ if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') {
87
+ header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path');
88
+ }
89
+ res.setHeader(String(key).trim(), header);
90
+ };
91
+ if (typeof rewriteCookieDomainConfig === 'string') {
92
+ //also test for ''
93
+ rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig };
94
+ }
95
+ if (typeof rewriteCookiePathConfig === 'string') {
96
+ //also test for ''
97
+ rewriteCookiePathConfig = { '*': rewriteCookiePathConfig };
98
+ }
99
+ // message.rawHeaders is added in: v0.11.6
100
+ // https://nodejs.org/api/http.html#http_message_rawheaders
101
+ if (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) {
102
+ rawHeaderKeyMap = {};
103
+ for (let i = 0; i < proxyRes.rawHeaders.length; i += 2) {
104
+ const key = proxyRes.rawHeaders[i];
105
+ rawHeaderKeyMap[key.toLowerCase()] = key;
106
+ }
107
+ }
108
+ Object.keys(proxyRes.headers).forEach(function (key) {
109
+ const header = proxyRes.headers[key];
110
+ if (preserveHeaderKeyCase && rawHeaderKeyMap) {
111
+ key = rawHeaderKeyMap[key] || key;
112
+ }
113
+ setHeader(key, header);
114
+ });
115
+ },
116
+ /**
117
+ * Set the statusCode from the proxyResponse
118
+ *
119
+ * @param {ClientRequest} req Request object
120
+ * @param {IncomingMessage} res Response object
121
+ * @param {proxyResponse} proxyRes Response object from the proxy request
122
+ *
123
+ * @api private
124
+ */
125
+ writeStatusCode: function writeStatusCode(req, res, proxyRes) {
126
+ // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers])
127
+ if (proxyRes.statusMessage) {
128
+ res.statusCode = proxyRes.statusCode;
129
+ res.statusMessage = proxyRes.statusMessage;
130
+ }
131
+ else {
132
+ res.statusCode = proxyRes.statusCode;
133
+ }
134
+ },
135
+ };
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ const http = require('http'), https = require('https'), common = require('../common');
3
+ /*!
4
+ * Array of passes.
5
+ *
6
+ * A `pass` is just a function that is executed on `req, socket, options`
7
+ * so that you can easily add new checks while still keeping the base
8
+ * flexible.
9
+ */
10
+ /*
11
+ * Websockets Passes
12
+ *
13
+ */
14
+ module.exports = {
15
+ /**
16
+ * WebSocket requests must have the `GET` method and
17
+ * the `upgrade:websocket` header
18
+ *
19
+ * @param {ClientRequest} req Request object
20
+ * @param {Socket} socket
21
+ *
22
+ * @api private
23
+ */
24
+ checkMethodAndHeader: function checkMethodAndHeader(req, socket) {
25
+ if (req.method !== 'GET' || !req.headers.upgrade) {
26
+ socket.destroy();
27
+ return true;
28
+ }
29
+ if (req.headers.upgrade.toLowerCase() !== 'websocket') {
30
+ socket.destroy();
31
+ return true;
32
+ }
33
+ },
34
+ /**
35
+ * Sets `x-forwarded-*` headers if specified in config.
36
+ *
37
+ * @param {ClientRequest} req Request object
38
+ * @param {Socket} socket
39
+ * @param {Object} options Config object passed to the proxy
40
+ *
41
+ * @api private
42
+ */
43
+ XHeaders: function XHeaders(req, socket, options) {
44
+ if (!options.xfwd)
45
+ return;
46
+ const values = {
47
+ for: req.connection.remoteAddress || req.socket.remoteAddress,
48
+ port: common.getPort(req),
49
+ proto: common.hasEncryptedConnection(req) ? 'wss' : 'ws',
50
+ };
51
+ ['for', 'port', 'proto'].forEach(function (header) {
52
+ req.headers['x-forwarded-' + header] =
53
+ (req.headers['x-forwarded-' + header] || '') +
54
+ (req.headers['x-forwarded-' + header] ? ',' : '') +
55
+ values[header];
56
+ });
57
+ },
58
+ /**
59
+ * Does the actual proxying. Make the request and upgrade it
60
+ * send the Switching Protocols request and pipe the sockets.
61
+ *
62
+ * @param {ClientRequest} req Request object
63
+ * @param {Socket} socket
64
+ * @param {Object} options Config object passed to the proxy
65
+ *
66
+ * @api private
67
+ */
68
+ stream: function stream(req, socket, options, head, server, clb) {
69
+ const createHttpHeader = function (line, headers) {
70
+ return (Object.keys(headers)
71
+ .reduce(function (head, key) {
72
+ const value = headers[key];
73
+ if (!Array.isArray(value)) {
74
+ head.push(key + ': ' + value);
75
+ return head;
76
+ }
77
+ for (let i = 0; i < value.length; i++) {
78
+ head.push(key + ': ' + value[i]);
79
+ }
80
+ return head;
81
+ }, [line])
82
+ .join('\r\n') + '\r\n\r\n');
83
+ };
84
+ common.setupSocket(socket);
85
+ if (head && head.length)
86
+ socket.unshift(head);
87
+ const proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request(common.setupOutgoing(options.ssl || {}, options, req));
88
+ // Enable developers to modify the proxyReq before headers are sent
89
+ if (server) {
90
+ server.emit('proxyReqWs', proxyReq, req, socket, options, head);
91
+ }
92
+ // Error Handler
93
+ proxyReq.on('error', onOutgoingError);
94
+ proxyReq.on('response', function (res) {
95
+ // if upgrade event isn't going to happen, close the socket
96
+ if (!res.upgrade) {
97
+ socket.write(createHttpHeader('HTTP/' +
98
+ res.httpVersion +
99
+ ' ' +
100
+ res.statusCode +
101
+ ' ' +
102
+ res.statusMessage, res.headers));
103
+ res.pipe(socket);
104
+ }
105
+ });
106
+ proxyReq.on('upgrade', function (proxyRes, proxySocket, proxyHead) {
107
+ proxySocket.on('error', onOutgoingError);
108
+ // Allow us to listen when the websocket has completed
109
+ proxySocket.on('end', function () {
110
+ server.emit('close', proxyRes, proxySocket, proxyHead);
111
+ });
112
+ // The pipe below will end proxySocket if socket closes cleanly, but not
113
+ // if it errors (eg, vanishes from the net and starts returning
114
+ // EHOSTUNREACH). We need to do that explicitly.
115
+ socket.on('error', function () {
116
+ proxySocket.end();
117
+ });
118
+ common.setupSocket(proxySocket);
119
+ if (proxyHead && proxyHead.length)
120
+ proxySocket.unshift(proxyHead);
121
+ //
122
+ // Remark: Handle writing the headers to the socket when switching protocols
123
+ // Also handles when a header is an array
124
+ //
125
+ socket.write(createHttpHeader('HTTP/1.1 101 Switching Protocols', proxyRes.headers));
126
+ proxySocket.pipe(socket).pipe(proxySocket);
127
+ server.emit('open', proxySocket);
128
+ server.emit('proxySocket', proxySocket); //DEPRECATED.
129
+ });
130
+ return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT
131
+ function onOutgoingError(err) {
132
+ if (clb) {
133
+ clb(err, req, socket);
134
+ }
135
+ else {
136
+ server.emit('error', err, req, socket);
137
+ }
138
+ socket.end();
139
+ }
140
+ },
141
+ };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*!
3
+ * Caron dimonio, con occhi di bragia
4
+ * loro accennando, tutte le raccoglie;
5
+ * batte col remo qualunque s’adagia
6
+ *
7
+ * Charon the demon, with the eyes of glede,
8
+ * Beckoning to them, collects them all together,
9
+ * Beats with his oar whoever lags behind
10
+ *
11
+ * Dante - The Divine Comedy (Canto III)
12
+ */
13
+ module.exports = './http-proxy';
@@ -0,0 +1,265 @@
1
+ const common = exports,
2
+ url = require('url'),
3
+ extend = require('util')._extend,
4
+ required = require('requires-port');
5
+
6
+ const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i,
7
+ isSSL = /^https|wss/;
8
+
9
+ /**
10
+ * Simple Regex for testing if protocol is https
11
+ */
12
+ common.isSSL = isSSL;
13
+ /**
14
+ * Copies the right headers from `options` and `req` to
15
+ * `outgoing` which is then used to fire the proxied
16
+ * request.
17
+ *
18
+ * Examples:
19
+ *
20
+ * common.setupOutgoing(outgoing, options, req)
21
+ * // => { host: ..., hostname: ...}
22
+ *
23
+ * @param {Object} Outgoing Base object to be filled with required properties
24
+ * @param {Object} Options Config object passed to the proxy
25
+ * @param {ClientRequest} Req Request Object
26
+ * @param {String} Forward String to select forward or target
27
+ *
28
+ * @return {Object} Outgoing Object with all required properties set
29
+ *
30
+ * @api private
31
+ */
32
+
33
+ common.setupOutgoing = function (outgoing, options, req, forward) {
34
+ outgoing.port =
35
+ options[forward || 'target'].port ||
36
+ (isSSL.test(options[forward || 'target'].protocol) ? 443 : 80);
37
+
38
+ [
39
+ 'host',
40
+ 'hostname',
41
+ 'socketPath',
42
+ 'pfx',
43
+ 'key',
44
+ 'passphrase',
45
+ 'cert',
46
+ 'ca',
47
+ 'ciphers',
48
+ 'secureProtocol',
49
+ ].forEach(function (e) {
50
+ outgoing[e] = options[forward || 'target'][e];
51
+ });
52
+
53
+ outgoing.method = options.method || req.method;
54
+ outgoing.headers = extend({}, req.headers);
55
+
56
+ if (options.headers) {
57
+ extend(outgoing.headers, options.headers);
58
+ }
59
+
60
+ if (options.auth) {
61
+ outgoing.auth = options.auth;
62
+ }
63
+
64
+ if (options.ca) {
65
+ outgoing.ca = options.ca;
66
+ }
67
+
68
+ if (isSSL.test(options[forward || 'target'].protocol)) {
69
+ outgoing.rejectUnauthorized =
70
+ typeof options.secure === 'undefined' ? true : options.secure;
71
+ }
72
+
73
+ outgoing.agent = options.agent || false;
74
+ outgoing.localAddress = options.localAddress;
75
+
76
+ //
77
+ // Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do
78
+ // as node core doesn't handle this COMPLETELY properly yet.
79
+ //
80
+ if (!outgoing.agent) {
81
+ outgoing.headers = outgoing.headers || {};
82
+ if (
83
+ typeof outgoing.headers.connection !== 'string' ||
84
+ !upgradeHeader.test(outgoing.headers.connection)
85
+ ) {
86
+ outgoing.headers.connection = 'close';
87
+ }
88
+ }
89
+
90
+ // the final path is target path + relative path requested by user:
91
+ const target = options[forward || 'target'];
92
+ const targetPath =
93
+ target && options.prependPath !== false ? target.path || '' : '';
94
+
95
+ //
96
+ // Remark: Can we somehow not use url.parse as a perf optimization?
97
+ //
98
+ let outgoingPath = !options.toProxy ? url.parse(req.url).path || '' : req.url;
99
+
100
+ //
101
+ // Remark: ignorePath will just straight up ignore whatever the request's
102
+ // path is. This can be labeled as FOOT-GUN material if you do not know what
103
+ // you are doing and are using conflicting options.
104
+ //
105
+ outgoingPath = !options.ignorePath ? outgoingPath : '';
106
+
107
+ outgoing.path = common.urlJoin(targetPath, outgoingPath);
108
+
109
+ if (options.changeOrigin) {
110
+ outgoing.headers.host =
111
+ required(outgoing.port, options[forward || 'target'].protocol) &&
112
+ !hasPort(outgoing.host)
113
+ ? outgoing.host + ':' + outgoing.port
114
+ : outgoing.host;
115
+ }
116
+ return outgoing;
117
+ };
118
+
119
+ /**
120
+ * Set the proper configuration for sockets,
121
+ * set no delay and set keep alive, also set
122
+ * the timeout to 0.
123
+ *
124
+ * Examples:
125
+ *
126
+ * common.setupSocket(socket)
127
+ * // => Socket
128
+ *
129
+ * @param {Socket} Socket instance to setup
130
+ *
131
+ * @return {Socket} Return the configured socket.
132
+ *
133
+ * @api private
134
+ */
135
+
136
+ common.setupSocket = function (socket) {
137
+ socket.setTimeout(0);
138
+ socket.setNoDelay(true);
139
+
140
+ socket.setKeepAlive(true, 0);
141
+
142
+ return socket;
143
+ };
144
+
145
+ /**
146
+ * Get the port number from the host. Or guess it based on the connection type.
147
+ *
148
+ * @param {Request} req Incoming HTTP request.
149
+ *
150
+ * @return {String} The port number.
151
+ *
152
+ * @api private
153
+ */
154
+ common.getPort = function (req) {
155
+ const res = req.headers.host ? req.headers.host.match(/:(\d+)/) : '';
156
+
157
+ return res ? res[1] : common.hasEncryptedConnection(req) ? '443' : '80';
158
+ };
159
+
160
+ /**
161
+ * Check if the request has an encrypted connection.
162
+ *
163
+ * @param {Request} req Incoming HTTP request.
164
+ *
165
+ * @return {Boolean} Whether the connection is encrypted or not.
166
+ *
167
+ * @api private
168
+ */
169
+ common.hasEncryptedConnection = function (req) {
170
+ return Boolean(req.connection.encrypted || req.connection.pair);
171
+ };
172
+
173
+ /**
174
+ * OS-agnostic join (doesn't break on URLs like path.join does on Windows)>
175
+ *
176
+ * @return {String} The generated path.
177
+ *
178
+ * @api private
179
+ */
180
+
181
+ common.urlJoin = function () {
182
+ //
183
+ // We do not want to mess with the query string. All we want to touch is the path.
184
+ //
185
+ const args = Array.prototype.slice.call(arguments),
186
+ lastIndex = args.length - 1,
187
+ last = args[lastIndex],
188
+ lastSegs = last.split('?');
189
+
190
+ args[lastIndex] = lastSegs.shift();
191
+
192
+ //
193
+ // Join all strings, but remove empty strings so we don't get extra slashes from
194
+ // joining e.g. ['', 'am']
195
+ //
196
+ const retSegs = [
197
+ args
198
+ .filter(Boolean)
199
+ .join('/')
200
+ .replace(/\/+/g, '/')
201
+ .replace('http:/', 'http://')
202
+ .replace('https:/', 'https://'),
203
+ ];
204
+
205
+ // Only join the query string if it exists so we don't have trailing a '?'
206
+ // on every request
207
+
208
+ // Handle case where there could be multiple ? in the URL.
209
+ retSegs.push.apply(retSegs, lastSegs);
210
+
211
+ return retSegs.join('?');
212
+ };
213
+
214
+ /**
215
+ * Rewrites or removes the domain of a cookie header
216
+ *
217
+ * @param {String|Array} header
218
+ * @param {Object} config, mapping of domain to rewritten domain.
219
+ * '*' key to match any domain, null value to remove the domain.
220
+ *
221
+ * @api private
222
+ */
223
+ common.rewriteCookieProperty = function rewriteCookieProperty(
224
+ header,
225
+ config,
226
+ property,
227
+ ) {
228
+ if (Array.isArray(header)) {
229
+ return header.map(function (headerElement) {
230
+ return rewriteCookieProperty(headerElement, config, property);
231
+ });
232
+ }
233
+ return header.replace(
234
+ new RegExp('(;\\s*' + property + '=)([^;]+)', 'i'),
235
+ function (match, prefix, previousValue) {
236
+ let newValue;
237
+ if (previousValue in config) {
238
+ newValue = config[previousValue];
239
+ } else if ('*' in config) {
240
+ newValue = config['*'];
241
+ } else {
242
+ //no match, return previous value
243
+ return match;
244
+ }
245
+ if (newValue) {
246
+ //replace value
247
+ return prefix + newValue;
248
+ } else {
249
+ //remove value
250
+ return '';
251
+ }
252
+ },
253
+ );
254
+ };
255
+
256
+ /**
257
+ * Check the host and see if it potentially has a port in it (keep it simple)
258
+ *
259
+ * @returns {Boolean} Whether we have one or not
260
+ *
261
+ * @api private
262
+ */
263
+ function hasPort(host) {
264
+ return !!~host.indexOf(':');
265
+ }