kuzzle 2.16.8 → 2.17.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/README.md +11 -0
- package/lib/api/controllers/adminController.js +7 -6
- package/lib/api/controllers/authController.js +11 -11
- package/lib/api/controllers/baseController.js +60 -3
- package/lib/api/controllers/clusterController.js +1 -1
- package/lib/api/controllers/collectionController.js +7 -5
- package/lib/api/controllers/documentController.js +130 -17
- package/lib/api/controllers/indexController.js +1 -1
- package/lib/api/controllers/memoryStorageController.js +39 -38
- package/lib/api/controllers/realtimeController.js +1 -1
- package/lib/api/controllers/securityController.js +49 -49
- package/lib/api/controllers/serverController.js +73 -27
- package/lib/api/documentExtractor.js +3 -3
- package/lib/api/funnel.js +40 -21
- package/lib/api/httpRoutes.js +9 -4
- package/lib/api/openapi/OpenApiManager.d.ts +11 -0
- package/lib/api/openapi/OpenApiManager.js +96 -0
- package/lib/api/openapi/{document → components/document}/count.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/create.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/createOrReplace.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/delete.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/deleteByQuery.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/exists.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/get.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/index.d.ts +2 -0
- package/lib/api/openapi/{document → components/document}/index.js +7 -2
- package/lib/api/openapi/{document → components/document}/replace.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/scroll.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/update.yaml +2 -2
- package/lib/api/openapi/components/document/validate.yaml +42 -0
- package/lib/api/openapi/components/index.d.ts +2 -0
- package/lib/api/openapi/components/index.js +18 -0
- package/lib/api/openapi/{payloads.yaml → components/payloads.yaml} +0 -0
- package/lib/api/openapi/index.d.ts +1 -2
- package/lib/api/openapi/index.js +1 -5
- package/lib/api/openapi/openApiGenerator.d.ts +7 -0
- package/lib/api/openapi/openApiGenerator.js +133 -0
- package/lib/api/request/kuzzleRequest.d.ts +11 -11
- package/lib/api/request/kuzzleRequest.js +38 -48
- package/lib/cluster/node.js +9 -9
- package/lib/cluster/publisher.js +1 -1
- package/lib/cluster/subscriber.js +1 -1
- package/lib/cluster/workers/IDCardRenewer.js +13 -4
- package/lib/config/default.config.js +1 -0
- package/lib/config/index.js +6 -6
- package/lib/core/auth/passportResponse.js +6 -6
- package/lib/core/auth/passportWrapper.js +5 -5
- package/lib/core/backend/backend.d.ts +5 -1
- package/lib/core/backend/backend.js +12 -8
- package/lib/core/backend/backendConfig.d.ts +5 -1
- package/lib/core/backend/backendConfig.js +4 -0
- package/lib/core/backend/backendOpenApi.d.ts +9 -0
- package/lib/core/backend/backendOpenApi.js +69 -0
- package/lib/core/backend/index.d.ts +1 -0
- package/lib/core/backend/index.js +1 -0
- package/lib/core/network/accessLogger.js +6 -6
- package/lib/core/network/clientConnection.js +1 -1
- package/lib/core/network/entryPoint.js +5 -5
- package/lib/core/network/httpRouter/index.js +5 -5
- package/lib/core/network/httpRouter/routeHandler.js +3 -3
- package/lib/core/network/httpRouter/routePart.js +5 -5
- package/lib/core/network/protocolManifest.js +1 -1
- package/lib/core/network/protocols/httpMessage.js +2 -2
- package/lib/core/network/protocols/httpwsProtocol.js +207 -46
- package/lib/core/network/protocols/mqttProtocol.js +3 -3
- package/lib/core/network/protocols/protocol.js +3 -3
- package/lib/core/network/router.js +7 -6
- package/lib/core/plugin/plugin.js +38 -64
- package/lib/core/plugin/pluginContext.d.ts +10 -1
- package/lib/core/plugin/pluginContext.js +2 -0
- package/lib/core/plugin/pluginManifest.js +3 -3
- package/lib/core/plugin/pluginRepository.js +5 -5
- package/lib/core/plugin/pluginsManager.js +29 -28
- package/lib/core/realtime/notification/server.js +1 -1
- package/lib/core/realtime/notification/user.js +1 -1
- package/lib/core/realtime/notifier.js +5 -5
- package/lib/core/security/index.js +1 -1
- package/lib/core/security/profileRepository.d.ts +176 -0
- package/lib/core/security/profileRepository.js +426 -443
- package/lib/core/security/roleRepository.js +16 -16
- package/lib/core/security/securityLoader.js +3 -3
- package/lib/core/security/tokenRepository.js +18 -21
- package/lib/core/security/userRepository.js +8 -8
- package/lib/core/shared/abstractManifest.js +4 -4
- package/lib/core/shared/repository.js +6 -6
- package/lib/core/shared/sdk/funnelProtocol.js +1 -1
- package/lib/core/shared/sdk/impersonatedSdk.js +1 -1
- package/lib/core/shared/store.js +30 -23
- package/lib/core/statistics/statistics.js +17 -17
- package/lib/core/storage/clientAdapter.js +45 -10
- package/lib/core/validation/baseType.js +5 -5
- package/lib/core/validation/types/anything.js +1 -1
- package/lib/core/validation/types/boolean.js +2 -2
- package/lib/core/validation/types/date.js +9 -9
- package/lib/core/validation/types/email.js +5 -5
- package/lib/core/validation/types/enum.js +6 -6
- package/lib/core/validation/types/geoPoint.js +2 -2
- package/lib/core/validation/types/geoShape.js +28 -25
- package/lib/core/validation/types/integer.js +4 -4
- package/lib/core/validation/types/ipAddress.js +7 -6
- package/lib/core/validation/types/numeric.js +4 -4
- package/lib/core/validation/types/object.js +5 -5
- package/lib/core/validation/types/string.js +5 -5
- package/lib/core/validation/types/url.js +7 -6
- package/lib/core/validation/validation.js +95 -84
- package/lib/kerror/codes/1-services.json +12 -0
- package/lib/kerror/codes/2-api.json +12 -0
- package/lib/kerror/codes/3-network.json +12 -0
- package/lib/kerror/codes/4-plugin.json +6 -0
- package/lib/kerror/codes/index.js +11 -11
- package/lib/kerror/index.js +1 -1
- package/lib/kuzzle/dumpGenerator.js +3 -3
- package/lib/kuzzle/event/kuzzleEventEmitter.js +4 -4
- package/lib/kuzzle/event/pipeRunner.js +1 -1
- package/lib/kuzzle/event/waterfall.js +6 -6
- package/lib/kuzzle/kuzzle.js +36 -5
- package/lib/kuzzle/log.js +3 -3
- package/lib/kuzzle/vault.js +3 -3
- package/lib/model/security/profile.d.ts +54 -0
- package/lib/model/security/profile.js +174 -233
- package/lib/model/security/rights.js +1 -1
- package/lib/model/security/role.d.ts +40 -0
- package/lib/model/security/role.js +159 -191
- package/lib/model/security/user.d.ts +29 -0
- package/lib/model/security/user.js +84 -52
- package/lib/model/storage/apiKey.js +2 -2
- package/lib/model/storage/baseModel.js +3 -3
- package/lib/service/cache/redis.js +7 -7
- package/lib/service/storage/elasticsearch.js +152 -90
- package/lib/service/storage/esWrapper.js +2 -3
- package/lib/types/ControllerDefinition.d.ts +3 -3
- package/lib/types/ControllerRights.d.ts +22 -0
- package/lib/types/ControllerRights.js +23 -0
- package/lib/types/HttpStream.d.ts +32 -0
- package/lib/types/HttpStream.js +70 -0
- package/lib/types/OpenApiDefinition.d.ts +43 -0
- package/lib/types/{config/StorageService/StorageServiceElasticsearchConfiguration.js → OpenApiDefinition.js} +1 -1
- package/lib/types/Policy.d.ts +25 -0
- package/lib/types/Policy.js +23 -0
- package/lib/types/PolicyRestrictions.d.ts +21 -0
- package/lib/types/PolicyRestrictions.js +23 -0
- package/lib/types/Target.d.ts +15 -0
- package/lib/types/Target.js +23 -0
- package/lib/types/config/KuzzleConfiguration.d.ts +4 -0
- package/lib/types/config/ServicesConfiguration.d.ts +2 -2
- package/lib/types/config/{StorageService/StorageServiceElasticsearchConfiguration.d.ts → storageEngine/StorageEngineElasticsearchConfiguration.d.ts} +10 -3
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.js +3 -0
- package/lib/types/index.d.ts +7 -1
- package/lib/types/index.js +7 -1
- package/lib/util/array.d.ts +11 -0
- package/lib/util/array.js +57 -0
- package/lib/util/assertType.js +6 -6
- package/lib/util/bufferedPassThrough.d.ts +76 -0
- package/lib/util/bufferedPassThrough.js +161 -0
- package/lib/util/deprecate.js +7 -5
- package/lib/util/didYouMean.js +1 -1
- package/lib/util/dump-collection.d.ts +3 -0
- package/lib/util/dump-collection.js +265 -0
- package/lib/util/extractFields.js +2 -2
- package/lib/util/inflector.d.ts +8 -0
- package/lib/util/inflector.js +16 -0
- package/lib/util/requestAssertions.js +7 -7
- package/lib/util/wildcard.js +55 -0
- package/package-lock.json +881 -431
- package/package.json +23 -20
- package/lib/api/openApiGenerator.d.ts +0 -7
- package/lib/api/openApiGenerator.js +0 -197
|
@@ -32,7 +32,7 @@ const { has } = require('../../../util/safeObject');
|
|
|
32
32
|
* @class RoutePart
|
|
33
33
|
*/
|
|
34
34
|
class RoutePart {
|
|
35
|
-
constructor() {
|
|
35
|
+
constructor () {
|
|
36
36
|
this.subparts = {};
|
|
37
37
|
this.placeholders = null;
|
|
38
38
|
|
|
@@ -45,7 +45,7 @@ class RoutePart {
|
|
|
45
45
|
* @param {string} part
|
|
46
46
|
* @returns {boolean}
|
|
47
47
|
*/
|
|
48
|
-
exists(part) {
|
|
48
|
+
exists (part) {
|
|
49
49
|
return this.subparts[part] !== undefined && this.subparts[part].handler !== null;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -56,8 +56,8 @@ class RoutePart {
|
|
|
56
56
|
* @param {string} part
|
|
57
57
|
* @returns {RoutePart}
|
|
58
58
|
*/
|
|
59
|
-
getNext(part) {
|
|
60
|
-
if (!has(this.subparts, part)) {
|
|
59
|
+
getNext (part) {
|
|
60
|
+
if (! has(this.subparts, part)) {
|
|
61
61
|
this.subparts[part] = new RoutePart();
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -71,7 +71,7 @@ class RoutePart {
|
|
|
71
71
|
* @param {HttpMessage} message
|
|
72
72
|
* @returns {RouteHandler} registered function handler
|
|
73
73
|
*/
|
|
74
|
-
getHandler(message) {
|
|
74
|
+
getHandler (message) {
|
|
75
75
|
// Do not use WHATWG API yet, stick with the legacy (and deprecated) URL
|
|
76
76
|
// There are two issues:
|
|
77
77
|
// - Heavy performance impact: https://github.com/nodejs/node/issues/30334
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const AbstractManifest = require('../shared/abstractManifest');
|
|
25
25
|
|
|
26
26
|
class ProtocolManifest extends AbstractManifest {
|
|
27
|
-
constructor(protocolPath, protocol) {
|
|
27
|
+
constructor (protocolPath, protocol) {
|
|
28
28
|
super(protocolPath);
|
|
29
29
|
|
|
30
30
|
this.protocol = protocol;
|
|
@@ -29,7 +29,7 @@ class HttpMessage {
|
|
|
29
29
|
* @param {ClientConnection} connection
|
|
30
30
|
* @param {uWS.HttpRequest} request
|
|
31
31
|
*/
|
|
32
|
-
constructor(connection, request) {
|
|
32
|
+
constructor (connection, request) {
|
|
33
33
|
this.connection = connection;
|
|
34
34
|
this._content = null;
|
|
35
35
|
this.ips = connection.ips;
|
|
@@ -54,7 +54,7 @@ class HttpMessage {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
set content (value) {
|
|
57
|
-
if (!value || value.length === 0) {
|
|
57
|
+
if (! value || value.length === 0) {
|
|
58
58
|
this._content = null;
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
@@ -27,6 +27,7 @@ const zlib = require('zlib');
|
|
|
27
27
|
|
|
28
28
|
const uWS = require('uWebSockets.js');
|
|
29
29
|
|
|
30
|
+
const { HttpStream } = require('../../../types');
|
|
30
31
|
const { Request } = require('../../../api/request');
|
|
31
32
|
const { KuzzleError } = require('../../../kerror/errors');
|
|
32
33
|
const Protocol = require('./protocol');
|
|
@@ -76,11 +77,15 @@ const HTTP_ALLOWED_CONTENT_TYPES = [
|
|
|
76
77
|
'application/x-www-form-urlencoded',
|
|
77
78
|
'multipart/form-data',
|
|
78
79
|
];
|
|
80
|
+
const HTTP_HEADER_CONNECTION = Buffer.from('Connection');
|
|
79
81
|
const HTTP_HEADER_CONTENT_LENGTH = Buffer.from('Content-Length');
|
|
80
82
|
const HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = Buffer.from('Access-Control-Allow-Origin');
|
|
81
83
|
const HTTP_HEADER_VARY = Buffer.from('Vary');
|
|
84
|
+
const HTTP_HEADER_TRANSFER_ENCODING = Buffer.from('Transfer-Encoding');
|
|
85
|
+
const CHUNKED = Buffer.from('chunked');
|
|
82
86
|
const WILDCARD = Buffer.from('*');
|
|
83
87
|
const ORIGIN = Buffer.from('Origin');
|
|
88
|
+
const CLOSE = Buffer.from('close');
|
|
84
89
|
const CHARSET_REGEX = /charset=([\w-]+)/i;
|
|
85
90
|
|
|
86
91
|
/**
|
|
@@ -119,7 +124,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
119
124
|
this.wsConfig = this.parseWebSocketOptions();
|
|
120
125
|
this.httpConfig = this.parseHttpOptions();
|
|
121
126
|
|
|
122
|
-
if (!this.wsConfig.enabled && !this.httpConfig.enabled) {
|
|
127
|
+
if (! this.wsConfig.enabled && ! this.httpConfig.enabled) {
|
|
123
128
|
return false;
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -135,7 +140,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
this.server.listen(entrypoint.config.port, socket => {
|
|
138
|
-
if (!socket) {
|
|
143
|
+
if (! socket) {
|
|
139
144
|
throw new Error(`[http/websocket] fatal: unable to listen to port ${entrypoint.config.port}`);
|
|
140
145
|
}
|
|
141
146
|
});
|
|
@@ -197,7 +202,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
197
202
|
const socket = this.socketByConnectionId.get(data.connectionId);
|
|
198
203
|
debugWS('notify: %a', data);
|
|
199
204
|
|
|
200
|
-
if (!socket) {
|
|
205
|
+
if (! socket) {
|
|
201
206
|
return;
|
|
202
207
|
}
|
|
203
208
|
|
|
@@ -212,7 +217,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
212
217
|
joinChannel (channel, connectionId) {
|
|
213
218
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
214
219
|
|
|
215
|
-
if (!socket) {
|
|
220
|
+
if (! socket) {
|
|
216
221
|
return;
|
|
217
222
|
}
|
|
218
223
|
|
|
@@ -223,7 +228,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
223
228
|
leaveChannel (channel, connectionId) {
|
|
224
229
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
225
230
|
|
|
226
|
-
if (!socket) {
|
|
231
|
+
if (! socket) {
|
|
227
232
|
return;
|
|
228
233
|
}
|
|
229
234
|
|
|
@@ -237,7 +242,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
237
242
|
|
|
238
243
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
239
244
|
|
|
240
|
-
if (!socket) {
|
|
245
|
+
if (! socket) {
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
243
248
|
|
|
@@ -260,7 +265,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
260
265
|
|
|
261
266
|
wsOnOpenHandler (socket) {
|
|
262
267
|
const ip = Buffer.from(socket.getRemoteAddressAsText()).toString();
|
|
263
|
-
const connection = new ClientConnection(this.name, [ip], {cookie: socket.cookie});
|
|
268
|
+
const connection = new ClientConnection(this.name, [ip], { cookie: socket.cookie });
|
|
264
269
|
|
|
265
270
|
this.entryPoint.newConnection(connection);
|
|
266
271
|
this.connectionBySocket.set(socket, connection);
|
|
@@ -271,7 +276,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
271
276
|
wsOnCloseHandler (socket, code, message) {
|
|
272
277
|
const connection = this.connectionBySocket.get(socket);
|
|
273
278
|
|
|
274
|
-
if (!connection) {
|
|
279
|
+
if (! connection) {
|
|
275
280
|
return;
|
|
276
281
|
}
|
|
277
282
|
|
|
@@ -289,7 +294,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
289
294
|
}
|
|
290
295
|
|
|
291
296
|
wsOnMessageHandler (socket, data) {
|
|
292
|
-
if (!data || data.byteLength === 0) {
|
|
297
|
+
if (! data || data.byteLength === 0) {
|
|
293
298
|
return;
|
|
294
299
|
}
|
|
295
300
|
|
|
@@ -403,7 +408,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
403
408
|
* @param {Buffer} payload
|
|
404
409
|
*/
|
|
405
410
|
wsSend (socket, payload) {
|
|
406
|
-
if (!this.connectionBySocket.has(socket)) {
|
|
411
|
+
if (! this.connectionBySocket.has(socket)) {
|
|
407
412
|
return;
|
|
408
413
|
}
|
|
409
414
|
|
|
@@ -442,7 +447,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
442
447
|
const contentType = message.headers['content-type'];
|
|
443
448
|
|
|
444
449
|
if ( contentType
|
|
445
|
-
&& !HTTP_ALLOWED_CONTENT_TYPES.some(allowed => contentType.includes(allowed))
|
|
450
|
+
&& ! HTTP_ALLOWED_CONTENT_TYPES.some(allowed => contentType.includes(allowed))
|
|
446
451
|
) {
|
|
447
452
|
this.httpSendError(
|
|
448
453
|
message,
|
|
@@ -499,7 +504,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
499
504
|
return;
|
|
500
505
|
}
|
|
501
506
|
|
|
502
|
-
if (!isLast) {
|
|
507
|
+
if (! isLast) {
|
|
503
508
|
return;
|
|
504
509
|
}
|
|
505
510
|
|
|
@@ -582,6 +587,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
582
587
|
return;
|
|
583
588
|
}
|
|
584
589
|
|
|
590
|
+
if (request.result instanceof HttpStream) {
|
|
591
|
+
this.httpSendStream(request, response, request.result, message);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Send the response in one go
|
|
596
|
+
|
|
585
597
|
const data = this.httpRequestToResponse(request, message);
|
|
586
598
|
|
|
587
599
|
this.httpCompress(message, data, result => {
|
|
@@ -592,36 +604,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
592
604
|
request.response.setHeader('Content-Encoding', result.encoding);
|
|
593
605
|
|
|
594
606
|
response.cork(() => {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
for (const header of this.httpConfig.headers) {
|
|
598
|
-
// If header is missing, add the default one
|
|
599
|
-
if (request.response.headers[header[2]] === undefined) {
|
|
600
|
-
response.writeHeader(header[0], header[1]);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// Access-Control-Allow-Origin Logic
|
|
605
|
-
if ( request.response.headers['Access-Control-Allow-Origin'] === undefined
|
|
606
|
-
&& message.headers
|
|
607
|
-
&& message.headers.origin
|
|
608
|
-
) {
|
|
609
|
-
response.writeHeader(
|
|
610
|
-
HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
|
|
611
|
-
Buffer.from(message.headers.origin));
|
|
612
|
-
|
|
613
|
-
response.writeHeader(HTTP_HEADER_VARY, ORIGIN);
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
for (const [key, value] of Object.entries(request.response.headers)) {
|
|
617
|
-
response.writeHeader(Buffer.from(key), Buffer.from(value.toString()));
|
|
618
|
-
}
|
|
607
|
+
this.httpWriteRequestHeaders(request, response, message);
|
|
619
608
|
|
|
620
609
|
const [ success ] = response.tryEnd(
|
|
621
610
|
result.compressed,
|
|
622
611
|
result.compressed.length);
|
|
623
612
|
|
|
624
|
-
if (!success) {
|
|
613
|
+
if (! success) {
|
|
625
614
|
response.onWritable(offset => {
|
|
626
615
|
const retryData = result.compressed.subarray(offset);
|
|
627
616
|
const [ retrySuccess ] = response.tryEnd(
|
|
@@ -636,6 +625,177 @@ class HttpWsProtocol extends Protocol {
|
|
|
636
625
|
});
|
|
637
626
|
}
|
|
638
627
|
|
|
628
|
+
/**
|
|
629
|
+
*
|
|
630
|
+
* @param {uWS.HttpRequest} request
|
|
631
|
+
* @param {uWS.HttpResponse} response
|
|
632
|
+
* @param {HttpMessage} message
|
|
633
|
+
*/
|
|
634
|
+
httpWriteRequestHeaders (request, response, message) {
|
|
635
|
+
response.writeStatus(Buffer.from(request.response.status.toString()));
|
|
636
|
+
|
|
637
|
+
response.writeHeader(HTTP_HEADER_CONNECTION, CLOSE);
|
|
638
|
+
|
|
639
|
+
for (const header of this.httpConfig.headers) {
|
|
640
|
+
// If header is missing, add the default one
|
|
641
|
+
if (request.response.headers[header[2]] === undefined) {
|
|
642
|
+
response.writeHeader(header[0], header[1]);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Access-Control-Allow-Origin Logic
|
|
647
|
+
if ( request.response.headers['Access-Control-Allow-Origin'] === undefined
|
|
648
|
+
&& message.headers
|
|
649
|
+
&& message.headers.origin
|
|
650
|
+
) {
|
|
651
|
+
response.writeHeader(
|
|
652
|
+
HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
|
|
653
|
+
Buffer.from(message.headers.origin));
|
|
654
|
+
|
|
655
|
+
response.writeHeader(HTTP_HEADER_VARY, ORIGIN);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
for (const [key, value] of Object.entries(request.response.headers)) {
|
|
659
|
+
response.writeHeader(Buffer.from(key), Buffer.from(value.toString()));
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Send stream data thorugh the HTTP response
|
|
665
|
+
* @param {HttpRequest} request
|
|
666
|
+
* @param {HttpStream} httpStream - The data stream to send
|
|
667
|
+
* @param {uWS.HttpResponse} response
|
|
668
|
+
* @param {HttpMessage} message
|
|
669
|
+
*/
|
|
670
|
+
httpSendStream (request, response, httpStream, message) {
|
|
671
|
+
const streamSizeFixed = typeof httpStream.totalBytes === 'number' && httpStream.totalBytes > 0;
|
|
672
|
+
|
|
673
|
+
if (httpStream.errored) {
|
|
674
|
+
this.httpSendError(
|
|
675
|
+
message,
|
|
676
|
+
response,
|
|
677
|
+
kerror.get('network', 'http', 'stream_errored', httpStream.error.message)
|
|
678
|
+
);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (httpStream.destroyed) {
|
|
683
|
+
this.httpSendError(
|
|
684
|
+
message,
|
|
685
|
+
response,
|
|
686
|
+
kerror.get('network', 'http', 'stream_closed')
|
|
687
|
+
);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Remove Content-Length header to avoid conflic with Transfer-Encoding header
|
|
692
|
+
request.response.setHeader('Content-Length', null);
|
|
693
|
+
|
|
694
|
+
// Send Headers in one go
|
|
695
|
+
response.cork(() => {
|
|
696
|
+
this.httpWriteRequestHeaders(request, response, message);
|
|
697
|
+
|
|
698
|
+
if (streamSizeFixed) {
|
|
699
|
+
response.writeHeader(HTTP_HEADER_CONTENT_LENGTH, Buffer.from(httpStream.totalBytes.toString()));
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
response.writeHeader(HTTP_HEADER_TRANSFER_ENCODING, CHUNKED);
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
httpStream.stream.on('data', chunk => {
|
|
707
|
+
// Make a copy of the array buffer
|
|
708
|
+
const arrayBuffer = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
|
|
709
|
+
|
|
710
|
+
const arrayBufferOffset = response.getWriteOffset();
|
|
711
|
+
|
|
712
|
+
let backpressure = false;
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Switch method of writing data to the response
|
|
716
|
+
* based on the size of the stream.
|
|
717
|
+
* If the stream has a fixed size we can use the tryEnd method
|
|
718
|
+
*/
|
|
719
|
+
if (streamSizeFixed) {
|
|
720
|
+
const [ success, done ] = response.tryEnd(arrayBuffer, httpStream.totalBytes);
|
|
721
|
+
backpressure = ! success;
|
|
722
|
+
|
|
723
|
+
if (done) {
|
|
724
|
+
httpStream.destroy();
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
const success = response.write(arrayBuffer);
|
|
730
|
+
|
|
731
|
+
backpressure = ! success;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// In case of backpressure we need to wait for drainage before sending more data
|
|
735
|
+
if (backpressure) {
|
|
736
|
+
response.arrayBufferOffset = arrayBufferOffset;
|
|
737
|
+
response.arrayBuffer = arrayBuffer;
|
|
738
|
+
httpStream.stream.pause();
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* When the stream is drained we can resume sending data,
|
|
742
|
+
* only if the is no backpressure after we wrote the missing chunk data.
|
|
743
|
+
*/
|
|
744
|
+
response.onWritable(offset => {
|
|
745
|
+
if (! streamSizeFixed && offset - response.arrayBufferOffset === 0) {
|
|
746
|
+
httpStream.stream.resume();
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
let retryBackpressure = false;
|
|
751
|
+
const remainingChunkData = response.arrayBuffer.slice(offset - response.arrayBufferOffset);
|
|
752
|
+
|
|
753
|
+
if (streamSizeFixed) {
|
|
754
|
+
const [ success ] = response.tryEnd(remainingChunkData, httpStream.totalBytes);
|
|
755
|
+
|
|
756
|
+
retryBackpressure = ! success;
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
const success = response.write(remainingChunkData);
|
|
760
|
+
|
|
761
|
+
retryBackpressure = ! success;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (! retryBackpressure) {
|
|
765
|
+
httpStream.stream.resume();
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
return ! retryBackpressure;
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
httpStream.stream.on('end', () => {
|
|
774
|
+
if (httpStream.destroy()) {
|
|
775
|
+
response.end();
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
httpStream.stream.on('close', () => {
|
|
780
|
+
if (httpStream.destroy()) {
|
|
781
|
+
response.end();
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
httpStream.stream.on('error', err => {
|
|
786
|
+
if (httpStream.destroy()) {
|
|
787
|
+
response.end();
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
debugHTTP('[%s] httpSendStream: %s', httpStream.connection.id, err.message);
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
response.onAborted(() => {
|
|
794
|
+
httpStream.destroy();
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
}
|
|
798
|
+
|
|
639
799
|
/**
|
|
640
800
|
* Forward an error response to the client
|
|
641
801
|
*
|
|
@@ -676,7 +836,8 @@ class HttpWsProtocol extends Protocol {
|
|
|
676
836
|
if (message.headers && message.headers.origin) {
|
|
677
837
|
if (global.kuzzle.config.internal.allowAllOrigins) {
|
|
678
838
|
response.writeHeader(HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, WILDCARD);
|
|
679
|
-
}
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
680
841
|
response.writeHeader(HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, Buffer.from(message.headers.origin));
|
|
681
842
|
response.writeHeader(HTTP_HEADER_VARY, ORIGIN);
|
|
682
843
|
}
|
|
@@ -699,13 +860,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
699
860
|
* @param {HttpMessage} message
|
|
700
861
|
* @returns {Buffer}
|
|
701
862
|
*/
|
|
702
|
-
httpRequestToResponse(request, message) {
|
|
863
|
+
httpRequestToResponse (request, message) {
|
|
703
864
|
let data = removeErrorStack(request.response.toJSON());
|
|
704
865
|
|
|
705
866
|
if (message.requestId !== data.requestId) {
|
|
706
867
|
data.requestId = message.requestId;
|
|
707
868
|
|
|
708
|
-
if (!data.raw) {
|
|
869
|
+
if (! data.raw) {
|
|
709
870
|
data.content.requestId = message.requestId;
|
|
710
871
|
}
|
|
711
872
|
}
|
|
@@ -759,7 +920,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
759
920
|
* @param {Buffer} data
|
|
760
921
|
* @param {Function} callback
|
|
761
922
|
*/
|
|
762
|
-
httpCompress(message, data, callback) {
|
|
923
|
+
httpCompress (message, data, callback) {
|
|
763
924
|
if (message.headers['accept-encoding']) {
|
|
764
925
|
const encodings = message.headers['accept-encoding']
|
|
765
926
|
.split(',')
|
|
@@ -788,15 +949,15 @@ class HttpWsProtocol extends Protocol {
|
|
|
788
949
|
|
|
789
950
|
if (algorithm === 'gzip') {
|
|
790
951
|
zlib.gzip(data, (err, compressed) => callback({
|
|
791
|
-
compressed: !err ? compressed : data,
|
|
792
|
-
encoding: !err ? 'gzip' : 'identity',
|
|
952
|
+
compressed: ! err ? compressed : data,
|
|
953
|
+
encoding: ! err ? 'gzip' : 'identity',
|
|
793
954
|
}));
|
|
794
955
|
return;
|
|
795
956
|
}
|
|
796
957
|
else if (algorithm === 'deflate') {
|
|
797
958
|
zlib.deflate(data, (err, compressed) => callback({
|
|
798
|
-
compressed: !err ? compressed : data,
|
|
799
|
-
encoding: !err ? 'deflate' : 'identity',
|
|
959
|
+
compressed: ! err ? compressed : data,
|
|
960
|
+
encoding: ! err ? 'deflate' : 'identity',
|
|
800
961
|
}));
|
|
801
962
|
return;
|
|
802
963
|
}
|
|
@@ -810,7 +971,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
810
971
|
|
|
811
972
|
httpUncompress (message, payload, cb) {
|
|
812
973
|
let encodings = message.headers['content-encoding'];
|
|
813
|
-
if (!encodings) {
|
|
974
|
+
if (! encodings) {
|
|
814
975
|
cb(null, payload);
|
|
815
976
|
return;
|
|
816
977
|
}
|
|
@@ -99,7 +99,7 @@ class MqttProtocol extends Protocol {
|
|
|
99
99
|
const payload = JSON.stringify(data.payload);
|
|
100
100
|
|
|
101
101
|
for (const channel of data.channels) {
|
|
102
|
-
this.aedes.publish({payload, topic: channel}, this.publishCallback);
|
|
102
|
+
this.aedes.publish({ payload, topic: channel }, this.publishCallback);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -126,14 +126,14 @@ class MqttProtocol extends Protocol {
|
|
|
126
126
|
|
|
127
127
|
const client = this.connectionsById.get(data.connectionId);
|
|
128
128
|
|
|
129
|
-
if (!client) {
|
|
129
|
+
if (! client) {
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
const payload = Buffer.from(JSON.stringify(data.payload));
|
|
134
134
|
|
|
135
135
|
data.channels.forEach(topic => {
|
|
136
|
-
client.publish({payload, topic}, this.publishCallback);
|
|
136
|
+
client.publish({ payload, topic }, this.publishCallback);
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -46,7 +46,7 @@ class Protocol {
|
|
|
46
46
|
*
|
|
47
47
|
* @returns {Promise<boolean>}
|
|
48
48
|
*/
|
|
49
|
-
async init(name, entryPoint) {
|
|
49
|
+
async init (name, entryPoint) {
|
|
50
50
|
this.entryPoint = entryPoint;
|
|
51
51
|
|
|
52
52
|
// name should be passed in the constructor
|
|
@@ -83,12 +83,12 @@ class Protocol {
|
|
|
83
83
|
|
|
84
84
|
joinChannel (channel, connectionId) {
|
|
85
85
|
// do nothing by default
|
|
86
|
-
return {channel, connectionId};
|
|
86
|
+
return { channel, connectionId };
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
leaveChannel (channel, connectionId) {
|
|
90
90
|
// do nothing by default
|
|
91
|
-
return {channel, connectionId};
|
|
91
|
+
return { channel, connectionId };
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
notify () {
|
|
@@ -31,7 +31,7 @@ const HttpRouter = require('./httpRouter');
|
|
|
31
31
|
* @param {Kuzzle} kuzzle
|
|
32
32
|
*/
|
|
33
33
|
class Router {
|
|
34
|
-
constructor() {
|
|
34
|
+
constructor () {
|
|
35
35
|
this.connections = new Map();
|
|
36
36
|
this.http = new HttpRouter();
|
|
37
37
|
}
|
|
@@ -42,13 +42,14 @@ class Router {
|
|
|
42
42
|
* @param {RequestContext} requestContext
|
|
43
43
|
*/
|
|
44
44
|
newConnection (requestContext) {
|
|
45
|
-
if (!requestContext.connection.id || !requestContext.connection.protocol) {
|
|
45
|
+
if (! requestContext.connection.id || ! requestContext.connection.protocol) {
|
|
46
46
|
global.kuzzle.log.error(kerror.get(
|
|
47
47
|
'protocol',
|
|
48
48
|
'runtime',
|
|
49
49
|
'invalid_connection',
|
|
50
50
|
JSON.stringify(requestContext)));
|
|
51
|
-
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
52
53
|
this.connections.set(requestContext.connection.id, requestContext);
|
|
53
54
|
global.kuzzle.statistics.newConnection(requestContext);
|
|
54
55
|
}
|
|
@@ -62,7 +63,7 @@ class Router {
|
|
|
62
63
|
removeConnection (requestContext) {
|
|
63
64
|
const connId = requestContext.connection.id;
|
|
64
65
|
|
|
65
|
-
if (!connId || !requestContext.connection.protocol) {
|
|
66
|
+
if (! connId || ! requestContext.connection.protocol) {
|
|
66
67
|
global.kuzzle.log.error(kerror.get(
|
|
67
68
|
'protocol',
|
|
68
69
|
'runtime',
|
|
@@ -71,7 +72,7 @@ class Router {
|
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
if (!this.connections.has(connId)) {
|
|
75
|
+
if (! this.connections.has(connId)) {
|
|
75
76
|
global.kuzzle.log.error(kerror.get(
|
|
76
77
|
'protocol',
|
|
77
78
|
'runtime',
|
|
@@ -131,7 +132,7 @@ class Router {
|
|
|
131
132
|
request.input.action = route.action;
|
|
132
133
|
|
|
133
134
|
if (route.deprecated) {
|
|
134
|
-
const { deprecated
|
|
135
|
+
const { deprecated: { since, message } } = route;
|
|
135
136
|
request.addDeprecation(since, message);
|
|
136
137
|
}
|
|
137
138
|
|