nodester 0.0.1 → 0.0.6

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 (58) hide show
  1. package/Readme.md +61 -26
  2. package/lib/application/index.js +86 -35
  3. package/lib/constants/Operations.js +23 -0
  4. package/lib/controllers/methods/index.js +170 -0
  5. package/lib/controllers/mixins/index.js +213 -0
  6. package/lib/enums/Enum.js +16 -0
  7. package/lib/factories/errors/CustomError.js +7 -5
  8. package/lib/factories/responses/html.js +7 -2
  9. package/lib/factories/responses/rest.js +110 -0
  10. package/lib/http/codes/index.js +157 -0
  11. package/lib/{application/http → http}/request.js +6 -30
  12. package/lib/{application/http → http}/response.js +20 -53
  13. package/lib/middlewares/etag/index.js +62 -0
  14. package/lib/middlewares/ql/sequelize/index.js +34 -0
  15. package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +121 -0
  16. package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +456 -0
  17. package/lib/models/define.js +6 -13
  18. package/lib/models/mixins.js +28 -15
  19. package/lib/params/Params.js +34 -0
  20. package/lib/queries/NodesterQueryParams.js +139 -0
  21. package/lib/router/handlers.util.js +61 -0
  22. package/lib/router/index.js +386 -0
  23. package/lib/router/route.js +124 -0
  24. package/lib/router/routes.util.js +66 -0
  25. package/lib/stacks/MarkersStack.js +35 -0
  26. package/lib/{application → stacks}/MiddlewareStack.js +47 -13
  27. package/lib/utils/path.util.js +3 -1
  28. package/lib/utils/types.util.js +51 -1
  29. package/lib/validators/dates.js +25 -0
  30. package/lib/validators/numbers.js +14 -0
  31. package/package.json +16 -2
  32. package/tests/index.test.js +7 -2
  33. package/tests/nql.test.js +277 -0
  34. package/docs/App.md +0 -13
  35. package/docs/Queries.md +0 -61
  36. package/docs/Readme.md +0 -2
  37. package/docs/Routing.md +0 -34
  38. package/examples/goal/index.js +0 -23
  39. package/examples/rest/index.js +0 -25
  40. package/examples/rest/node_modules/.package-lock.json +0 -40
  41. package/examples/rest/package-lock.json +0 -72
  42. package/examples/rest/package.json +0 -14
  43. package/lib/constants/ConstantsEnum.js +0 -13
  44. package/lib/factories/responses/api.js +0 -90
  45. package/lib/routers/Default/index.js +0 -143
  46. package/lib/routers/Default/layer.js +0 -50
  47. package/lib/routers/Main/index.js +0 -10
  48. package/lib/routers/Roles/index.js +0 -81
  49. package/lib/utils/params.util.js +0 -19
  50. /package/lib/{controllers/Controller.js → _/n_controllers/Controller.js"} +0 -0
  51. /package/lib/{controllers/JWTController.js → _/n_controllers/JWTController.js"} +0 -0
  52. /package/lib/{controllers/ServiceController.js → _/n_controllers/ServiceController.js"} +0 -0
  53. /package/lib/{controllers/WebController.js → _/n_controllers/WebController.js"} +0 -0
  54. /package/lib/{facades → _facades}/Facade.js +0 -0
  55. /package/lib/{facades → _facades}/FacadeParams.js +0 -0
  56. /package/lib/{facades → _facades}/ServiceFacade.js +0 -0
  57. /package/lib/{facades → _facades}/jwt.facade.js +0 -0
  58. /package/lib/{application/http → http}/utils.js +0 -0
@@ -0,0 +1,213 @@
1
+ const {
2
+ getOne,
3
+ getMany,
4
+ createOne,
5
+ updateOne,
6
+ deleteOne
7
+ } = require('../methods');
8
+
9
+
10
+ module.exports = {
11
+ withDefaultCRUD: _withDefaultCRUD,
12
+ withDefaultErrorProcessing: _withDefaultErrorProcessing,
13
+ setMethod: _setMethod
14
+ }
15
+
16
+
17
+ /**
18
+ * Sets one of or all of CRUD methods to Controller.
19
+ *
20
+ * @param {Function|Object} controller
21
+ * @param {Object} opts
22
+ * - @param {Function|Object} facade
23
+ * - @param {String} name
24
+ * - @param {Array} only
25
+ *
26
+ * @return {Function|Object} controller
27
+ *
28
+ * @api public
29
+ * @alias withDefaultCRUD
30
+ */
31
+ function _withDefaultCRUD(controller, opts={}) {
32
+ const {
33
+ facade,
34
+
35
+ // Optional:
36
+ name,
37
+ only
38
+ } = opts;
39
+
40
+ if (!controller) {
41
+ const err = new TypeError(`'controller' argument is not provided.`);
42
+ throw err;
43
+ }
44
+
45
+ if (!facade) {
46
+ const err = new TypeError(`'opts.facade' argument is invalid.`);
47
+ throw err;
48
+ }
49
+
50
+ // Set main facade:
51
+ if (facade.constructor.name === 'Function') {
52
+ controller.facade = new facade();
53
+ }
54
+ else {
55
+ controller.facade = facade;
56
+ }
57
+
58
+ // Set model info:
59
+ const model = facade.model;
60
+ // Extract plural name of this model.
61
+ const modelPluralName = model?.options?.name?.plural;
62
+ // Set name of this controller:
63
+ Object.defineProperty(controller, 'name', {
64
+ value: name ?? `${ modelPluralName ?? controller.name }Controller`,
65
+ writable: false
66
+ });
67
+
68
+
69
+ // If only certain methods should be set:
70
+ if (!!only) {
71
+ for (const selectedMethod of only) {
72
+ switch(selectedMethod) {
73
+ case 'getOne':
74
+ controller.getOne = getOne.bind(controller);
75
+ break;
76
+ case 'getMany':
77
+ controller.getMany = getMany.bind(controller);
78
+ break;
79
+ case 'createOne':
80
+ controller.createOne = createOne.bind(controller);
81
+ break;
82
+ case 'updateOne':
83
+ controller.updateOne = updateOne.bind(controller);
84
+ break;
85
+ case 'deleteOne':
86
+ controller.deleteOne = deleteOne.bind(controller);
87
+ break;
88
+
89
+ default:
90
+ break;
91
+ }
92
+ }
93
+ }
94
+ // Or set all methods:
95
+ else {
96
+ controller.getOne = getOne.bind(controller);
97
+ controller.getMany = getMany.bind(controller);
98
+ controller.createOne = createOne.bind(controller);
99
+ controller.updateOne = updateOne.bind(controller);
100
+ controller.deleteOne = deleteOne.bind(controller);
101
+
102
+ // Set empty hooks:
103
+ controller.afterGetOne = async () => {};
104
+ controller.afterGetMany = async () => {};
105
+ controller.afterCreateOne = async () => {};
106
+ controller.afterUpdateOne = async () => {};
107
+ controller.afterDeleteOe = async () => {};
108
+ }
109
+
110
+ // TODO: remove.
111
+ controller.respondOk = (res, data) => res.json(data);
112
+ controller.respondNotOk = (res, data) => { res.status(data.status); res.json(data); };
113
+
114
+ return controller;
115
+ }
116
+
117
+
118
+ /**
119
+ * Sets default error responses to Controller.
120
+ *
121
+ * @param {Function|Object} controller
122
+ * @param {Object} opts
123
+ *
124
+ * @return {Function|Object} controller
125
+ *
126
+ * @api public
127
+ * @alias withDefaultErrorProcessing
128
+ */
129
+ function _withDefaultErrorProcessing(controller, opts={}) {
130
+ if (!controller) {
131
+ const err = new TypeError(`'controller' argument is not provided.`);
132
+ throw err;
133
+ }
134
+
135
+ // Set processError:
136
+ controller.processError = function (error, req, res) {
137
+ // Default error message.
138
+ let errorMessage = error?.message ?? 'Internal server error';
139
+ // Default HTTP status code.
140
+ let statusCode = error?.status ?? error?.statusCode ?? 500;
141
+ // Error response object.
142
+ let errorResponse = {};
143
+
144
+ switch(error.name) {
145
+ case('Unauthorized'): {
146
+ statusCode = 401;
147
+ errorResponse.details = { message: 'Unauthorized' };
148
+ break;
149
+ }
150
+ case('NotFound'): {
151
+ statusCode = 404;
152
+ errorResponse.details = { message: errorMessage };
153
+ break;
154
+ }
155
+ case('ValidationError'): {
156
+ statusCode = 406;
157
+ errorResponse.details = error?.details;
158
+ break;
159
+ }
160
+ case('ConflictError'): {
161
+ statusCode = 409;
162
+ errorResponse.details = error?.details ?? error?.message;
163
+ break;
164
+ }
165
+ case('SequelizeUniqueConstraintError'): {
166
+ statusCode = 409;
167
+ errorResponse.details = error?.errors;
168
+ break;
169
+ }
170
+ case('InternalValidationError'): {
171
+ statusCode = 500;
172
+ errorResponse.details = { message:'Error' };
173
+ break;
174
+ }
175
+ default: {
176
+ errorResponse.details = { message:errorMessage };
177
+ break;
178
+ }
179
+ }
180
+
181
+ // Send error response with provided status code.
182
+ return this.respondNotOk(res, {
183
+ error: {
184
+ ...errorResponse,
185
+ code: statusCode
186
+ },
187
+ status: statusCode
188
+ });
189
+ }
190
+
191
+ return controller;
192
+ }
193
+
194
+
195
+ /**
196
+ * Sets one of CRUD methods to Controller.
197
+ *
198
+ * @param {Function|Object} controller
199
+ * @param {Object} opts
200
+ *
201
+ * @return {Function|Object} controller
202
+ *
203
+ * @api public
204
+ * @alias withDefaultCRUD
205
+ */
206
+ function _setMethod(controller,) {
207
+ if (!controller) {
208
+ const err = new TypeError(`'controller' argument is not provided.`);
209
+ throw err;
210
+ }
211
+
212
+
213
+ }
@@ -0,0 +1,16 @@
1
+
2
+ module.exports = Enum;
3
+
4
+ function Enum(constantsList = {}, writable=false) {
5
+ const def = (key, value) => Object.defineProperty(this, key, { value, writable: !!writable });
6
+
7
+ // Set list.
8
+ def('list', constantsList);
9
+
10
+ // Set getters:
11
+ Object.keys(constantsList)
12
+ .forEach(key => def(key, constantsList[key]) );
13
+
14
+ // Set constants in static array.
15
+ def('asArray', Object.values(constantsList) );
16
+ }
@@ -1,6 +1,8 @@
1
- class CustomError extends Error {
1
+
2
+ module.exports = class CustomError extends Error {
2
3
  constructor(message) {
3
4
  super(message);
5
+
4
6
  this.name = this.constructor.name;
5
7
  this.status = 500;
6
8
 
@@ -14,9 +16,9 @@ class CustomError extends Error {
14
16
  this.status = originalError?.status ?? this.status;
15
17
 
16
18
  // Append stack from original error.
17
- const messageLines = (this.message.match(/\n/g)||[]).length + 1
18
- this.stack = this.stack.split('\n').slice(0, messageLines+1).join('\n') + '\n' + originalError.stack;
19
+ const linesCount = (this.message.match(/\n/g)||[]).length + 1;
20
+ this.stack = this.stack.split('\n')
21
+ .slice(0, linesCount+1)
22
+ .join('\n') + '\n' + originalError.stack;
19
23
  }
20
24
  }
21
-
22
- module.exports = CustomError;
@@ -1,7 +1,12 @@
1
- const Params = require('nodester/facades/FacadeParams');
1
+ /*
2
+ * WARNING: Unfinihsed. Do not use!
3
+ *
4
+ */
2
5
 
6
+ const Params = require('../../params/Params');
3
7
 
4
- module.exports = class WebResponseFactory {
8
+
9
+ module.exports = class HtmlResponseFactory {
5
10
  constructor() {}
6
11
 
7
12
  /**
@@ -0,0 +1,110 @@
1
+ /*
2
+ * Rest response factory.
3
+ */
4
+
5
+ const ResponseFormats = require('../../constants/ResponseFormats');
6
+
7
+
8
+ module.exports = {
9
+ createGenericResponse: _createGenericResponse,
10
+ createOKResponse: _createOKResponse,
11
+ createErrorResponse: _createErrorResponse,
12
+ }
13
+
14
+
15
+ /*
16
+ * Format for all API responses will be JSON
17
+ * {
18
+ * content: {...}
19
+ * error: {...}
20
+ * }
21
+ * Status code is sent in header.
22
+ *
23
+ * If error is not present, error should be null.
24
+ * If error is present, content can be null (But it's not required).
25
+ *
26
+ * @param {ServerResponse} res
27
+ * @param {Object} options
28
+ *
29
+ * @alias createGenericResponse
30
+ * @api public
31
+ */
32
+ function _createGenericResponse(
33
+ res,
34
+ options = {
35
+ status: 200,
36
+ content: {},
37
+ error: null,
38
+ format: ResponseFormats.JSON
39
+ }
40
+ ) {
41
+ try {
42
+ const data = {
43
+ content: options?.content ?? null,
44
+ error: options?.error ?? null
45
+ };
46
+
47
+ switch(options?.format) {
48
+ case ResponseFormats.JSON:
49
+ return options?.res.status(options?.status).json(data);
50
+ case ResponseFormats.XML:
51
+ // TODO: format data into XML.
52
+ return options?.res.status(options?.status).send(data);
53
+ break;
54
+ default: {
55
+ const err = new TypeError("No format specified.");
56
+ throw err;
57
+ }
58
+ }
59
+ }
60
+ catch(error) {
61
+ const err = new Error(`Could not create generic response: ${error.message}`);
62
+ err.name = error?.name;
63
+ err.code = error?.code;
64
+ throw err;
65
+ }
66
+ }
67
+
68
+
69
+ /**
70
+ * Sends response with status code 200.
71
+ * Should be called on all successful respones.
72
+ *
73
+ * @param {ServerResponse} res
74
+ * @param <Object> content
75
+ * @param <String> format
76
+ *
77
+ * @alias createOKResponse
78
+ * @api public
79
+ */
80
+ function _createOKResponse(res, options={}) {
81
+
82
+ return this.createGenericResponse(res, {
83
+ ...options,
84
+ status: 200,
85
+ format: options?.format ?? ResponseFormats.JSON
86
+ });
87
+ }
88
+
89
+
90
+ /**
91
+ * Sends response with provided error code.
92
+ * Should be called on all failed respones.
93
+ *
94
+ * @param {ServerResponse} res
95
+ * @param <Object> error
96
+ * @param <Object> content (optional)
97
+ * @param <Int> status
98
+ * @param <String> format
99
+ *
100
+ * @alias createErrorResponse
101
+ * @api public
102
+ */
103
+ function _createErrorResponse(res, options) {
104
+
105
+ return this.createGenericResponse(res, {
106
+ ...options,
107
+ status: options?.status ?? 500,
108
+ format: options?.format ?? ResponseFormats.JSON
109
+ });
110
+ }
@@ -0,0 +1,157 @@
1
+ const symbolsByTag = {
2
+ // Informational:
3
+ CONTINUE: Symbol('100: Continue'),
4
+ SWITCHING_PROTOCOLS: Symbol('101: Switching Protocols'),
5
+ PROCESSING: Symbol('102: Processing'),
6
+ EARLY_HINTS: Symbol('103: Early Hints'),
7
+
8
+ // Success:
9
+ OK: Symbol('200: OK'),
10
+ CREATED: Symbol('201: Created'),
11
+ ACCEPTED: Symbol('202: Accepted'),
12
+ NON_AUTHORITATIVE_INFORMATION: Symbol('203: Non-Authoritative Information'),
13
+ NO_CONTENT: Symbol('204: No Content'),
14
+ RESET_CONTENT: Symbol('205: Reset Content'),
15
+ PARTIAL_CONTENT: Symbol('206: Partial Content'),
16
+ MULTI_STATUS: Symbol('207: Multi-Status'),
17
+ ALREADY_REPORTED: Symbol('208: Already Reported'),
18
+ IM_USED: Symbol('226: IM Used'),
19
+
20
+ // Redirections:
21
+ MULTIPLE_CHOICES: Symbol('300: Multiple Choices'),
22
+ MOVED_PERMANENTLY: Symbol('301: Moved Permanently'),
23
+ FOUND: Symbol('302: Found'),
24
+ SEE_OTHER: Symbol('303: See Other'),
25
+ NOT_MODIFIED: Symbol('304: Not Modified'),
26
+ USE_PROXY: Symbol('305: Use Proxy'),
27
+ TEMPORARY_REDIRECT: Symbol('307: Temporary Redirect'),
28
+ PERMANENT_REDIRECT: Symbol('308: Permanent Redirect'),
29
+
30
+ // Client Errors:
31
+ BAD_REQUEST: Symbol('400: Bad Request'),
32
+ UNAUTHORIZED: Symbol('401: Unauthorized'),
33
+ PAYMENT_REQUIRED: Symbol('402: Payment Required'),
34
+ FORBIDDEN: Symbol('403: Forbidden'),
35
+ NOT_FOUND: Symbol('404: Not Found'),
36
+ METHOD_NOT_ALLOWED: Symbol('405: Method Not Allowed'),
37
+ NOT_ACCEPTABLE: Symbol('406: Not Acceptable'),
38
+ PROXY_AUTHENTICATION_REQUIRED: Symbol('407: Proxy Authentication Required'),
39
+ REQUEST_TIMEOUT: Symbol('408: Request Timeout'),
40
+ CONFLICT: Symbol('409: Conflict'),
41
+ GONE: Symbol('410: Gone'),
42
+ LENGTH_REQUIRED: Symbol('411: Length Required'),
43
+ PRECONDITION_FAILED: Symbol('412: Precondition Failed'),
44
+ PAYLOAD_TOO_LARGE: Symbol('413: Payload Too Large'),
45
+ URI_TOO_LONG: Symbol('414: URI Too Long'),
46
+ UNSUPPORTED_MEDIA_TYPE: Symbol('415: Unsupported Media Type'),
47
+ RANGE_NOT_SATISFIABLE: Symbol('416: Range Not Satisfiable'),
48
+ EXPECTATION_FAILED: Symbol('417: Expectation Failed'),
49
+ IM_A_TEAPOT: Symbol("418: I'm a teapot"),
50
+ MISDIRECTED_REQUEST: Symbol('421: Misdirected Request'),
51
+ UNPROCESSABLE_ENTITY: Symbol('422: Unprocessable Entity'),
52
+ LOCKED: Symbol('423: Locked'),
53
+ FAILED_DEPENDENCY: Symbol('424: Failed Dependency'),
54
+ TOO_EARLY: Symbol('425: Too Early'),
55
+ UPGRADE_REQUIRED: Symbol('426: Upgrade Required'),
56
+ PRECONDITION_REQUIRED: Symbol('428: Precondition Required'),
57
+ TOO_MANY_REQUESTS: Symbol('429: Too Many Requests'),
58
+ REQUEST_HEADER_FIELDS_TOO_LARGE: Symbol('431: Request Header Fields Too Large'),
59
+ UNAVAILABLE_FOR_LEGAL_REASONS: Symbol('451: Unavailable For Legal Reasons'),
60
+
61
+ // Server Errors:
62
+ INTERNAL_SERVER_ERROR: Symbol('500: Internal Server Error'),
63
+ NOT_IMPLEMENTED: Symbol('501: Not Implemented'),
64
+ BAD_GATEWAY: Symbol('502: Bad Gateway'),
65
+ SERVICE_UNAVAILABLE: Symbol('503: Service Unavailable'),
66
+ GATEWAY_TIMEOUT: Symbol('504: Gateway Timeout'),
67
+ HTTP_VERSION_NOT_SUPPORTED: Symbol('505: HTTP Version Not Supported'),
68
+ VARIANT_ALSO_NEGOTIATES: Symbol('506: Variant Also Negotiates'),
69
+ INSUFFICIENT_STORAGE: Symbol('507: Insufficient Storage'),
70
+ LOOP_DETECTED: Symbol('508: Loop Detected'),
71
+ NOT_EXTENDED: Symbol('510: Not Extended'),
72
+ NETWORK_AUTHENTICATION_REQUIRED: Symbol('511: Network Authentication Required')
73
+ }
74
+
75
+ const descriptionsByCode = {
76
+ // Informational:
77
+ 100: 'Continue',
78
+ 101: 'Switching Protocols',
79
+ 102: 'Processing',
80
+ 103: 'Early Hints',
81
+
82
+ // Success:
83
+ 200: 'OK',
84
+ 201: 'Created',
85
+ 202: 'Accepted',
86
+ 203: 'Non-Authoritative Information',
87
+ 204: 'No Content',
88
+ 205: 'Reset Content',
89
+ 206: 'Partial Content',
90
+ 207: 'Multi-Status',
91
+ 208: 'Already Reported',
92
+ 226: 'IM Used',
93
+
94
+ // Redirections:
95
+ 300: 'Multiple Choices',
96
+ 301: 'Moved Permanently',
97
+ 302: 'Found',
98
+ 303: 'See Other',
99
+ 304: 'Not Modified',
100
+ 305: 'Use Proxy',
101
+ 307: 'Temporary Redirect',
102
+ 308: 'Permanent Redirect',
103
+
104
+ // Client Errors:
105
+ 400: 'Bad Request',
106
+ 401: 'Unauthorized',
107
+ 402: 'Payment Required',
108
+ 403: 'Forbidden',
109
+ 404: 'Not Found',
110
+ 405: 'Method Not Allowed',
111
+ 406: 'Not Acceptable',
112
+ 407: 'Proxy Authentication Required',
113
+ 408: 'Request Timeout',
114
+ 409: 'Conflict',
115
+ 410: 'Gone',
116
+ 411: 'Length Required',
117
+ 412: 'Precondition Failed',
118
+ 413: 'Payload Too Large',
119
+ 414: 'URI Too Long',
120
+ 415: 'Unsupported Media Type',
121
+ 416: 'Range Not Satisfiable',
122
+ 417: 'Expectation Failed',
123
+ 418: 'I\'m a teapot',
124
+ 421: 'Misdirected Request',
125
+ 422: 'Unprocessable Entity',
126
+ 423: 'Locked',
127
+ 424: 'Failed Dependency',
128
+ 425: 'Too Early',
129
+ 426: 'Upgrade Required',
130
+ 428: 'Precondition Required',
131
+ 429: 'Too Many Requests',
132
+ 431: 'Request Header Fields Too Large',
133
+ 451: 'Unavailable For Legal Reasons',
134
+
135
+ // Server Errors:
136
+ 500: 'Internal Server Error',
137
+ 501: 'Not Implemented',
138
+ 502: 'Bad Gateway',
139
+ 503: 'Service Unavailable',
140
+ 504: 'Gateway Timeout',
141
+ 505: 'HTTP Version Not Supported',
142
+ 506: 'Variant Also Negotiates',
143
+ 507: 'Insufficient Storage',
144
+ 508: 'Loop Detected',
145
+ 510: 'Not Extended',
146
+ 511: 'Network Authentication Required'
147
+ };
148
+
149
+ module.exports = {
150
+ descriptions: {
151
+ byCode: descriptionsByCode
152
+ },
153
+
154
+ symbols: {
155
+ byTag: symbolsByTag
156
+ }
157
+ }
@@ -7,14 +7,14 @@
7
7
  const accepts = require('accepts');
8
8
  const isIP = require('net').isIP;
9
9
  const typeis = require('type-is');
10
- const http = require('http');
10
+ const { IncomingMessage } = require('http');
11
11
  const fresh = require('fresh');
12
12
  const parseRange = require('range-parser');
13
13
  const parse = require('parseurl');
14
14
  const proxyaddr = require('proxy-addr');
15
15
 
16
16
 
17
- const req = http.IncomingMessage.prototype;
17
+ const req = IncomingMessage.prototype;
18
18
 
19
19
  module.exports = req;
20
20
 
@@ -355,39 +355,15 @@ defineGetter(req, 'path', function path() {
355
355
 
356
356
  /**
357
357
  * Parse the "Host" header field to a hostname.
358
- *
359
- * When the "trust proxy" setting trusts the socket
360
- * address, the "X-Forwarded-Host" header field will
361
- * be trusted.
358
+ * Will return "X-Forwarded-Host" if set,
359
+ * or "Host" as a fallback.
362
360
  *
363
361
  * @return {String}
364
362
  * @public
365
363
  */
366
364
  defineGetter(req, 'hostname', function hostname() {
367
- const trust = this.app.get('trust proxy fn');
368
- let host = this.get('X-Forwarded-Host');
369
-
370
- if (!host || !trust(this.connection.remoteAddress, 0)) {
371
- host = this.get('Host');
372
- }
373
- else if (host.indexOf(',') !== -1) {
374
- // Note: X-Forwarded-Host is normally only ever a
375
- // single value, but this is to be safe.
376
- host = host.substring(0, host.indexOf(',')).trimRight()
377
- }
378
-
379
- if (!host)
380
- return;
381
-
382
- // IPv6 literal support
383
- const offset = host[0] === '['
384
- ? host.indexOf(']') + 1
385
- : 0;
386
- const index = host.indexOf(':', offset);
387
-
388
- return index !== -1
389
- ? host.substring(0, index)
390
- : host;
365
+ const host = this.get('X-Forwarded-Host') ?? this.get('Host');
366
+ return host;
391
367
  });
392
368
 
393
369