kuzzle 2.16.10 → 2.17.1
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/lib/api/controllers/adminController.js +3 -3
- package/lib/api/controllers/authController.js +12 -12
- 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 +50 -50
- 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.js +8 -6
- package/lib/cluster/node.js +9 -9
- package/lib/cluster/publisher.js +1 -1
- package/lib/cluster/state.js +20 -4
- package/lib/cluster/subscriber.js +1 -1
- package/lib/cluster/workers/IDCardRenewer.js +2 -2
- 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 +11 -3
- package/lib/core/backend/backend.js +22 -17
- package/lib/core/backend/backendConfig.d.ts +5 -1
- package/lib/core/backend/backendConfig.js +25 -2
- package/lib/core/backend/backendController.js +21 -5
- package/lib/core/backend/backendErrors.d.ts +58 -0
- package/lib/core/backend/backendErrors.js +121 -0
- package/lib/core/backend/backendHook.js +21 -5
- package/lib/core/backend/backendImport.js +21 -5
- package/lib/core/backend/backendOpenApi.d.ts +9 -0
- package/lib/core/backend/backendOpenApi.js +69 -0
- package/lib/core/backend/backendPipe.js +21 -5
- package/lib/core/backend/backendPlugin.js +22 -3
- package/lib/core/backend/backendVault.js +21 -2
- package/lib/core/backend/index.d.ts +2 -0
- package/lib/core/backend/index.js +2 -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 +222 -48
- 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.js +22 -3
- 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/channel.js +20 -4
- package/lib/core/realtime/hotelClerk.js +24 -5
- 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 +445 -443
- package/lib/core/security/roleRepository.js +16 -16
- package/lib/core/security/securityLoader.js +2 -2
- package/lib/core/security/tokenRepository.js +11 -11
- package/lib/core/security/userRepository.js +8 -8
- package/lib/core/shared/abstractManifest.js +4 -4
- package/lib/core/shared/repository.js +5 -5
- package/lib/core/shared/sdk/embeddedSdk.js +21 -2
- 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/storage/indexCache.js +20 -4
- 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/errors/multipleErrorsError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.js +3 -3
- package/lib/kerror/index.d.ts +82 -0
- package/lib/kerror/index.js +176 -143
- 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 +59 -9
- 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 +192 -232
- package/lib/model/security/rights.js +1 -1
- package/lib/model/security/role.d.ts +40 -0
- package/lib/model/security/role.js +174 -190
- package/lib/model/security/user.d.ts +29 -0
- package/lib/model/security/user.js +103 -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/Plugin.js +20 -4
- 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/errors/ErrorDefinition.d.ts +27 -0
- package/lib/types/errors/ErrorDefinition.js +3 -0
- package/lib/types/errors/ErrorDomains.d.ts +17 -0
- package/lib/types/errors/ErrorDomains.js +3 -0
- package/lib/types/index.d.ts +9 -1
- package/lib/types/index.js +9 -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 +284 -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/mutex.js +21 -2
- package/lib/util/requestAssertions.js +7 -7
- package/lib/util/wildcard.js +55 -0
- package/package-lock.json +517 -75
- package/package.json +5 -3
- package/lib/api/openApiGenerator.d.ts +0 -7
- package/lib/api/openApiGenerator.js +0 -197
|
@@ -38,7 +38,7 @@ const kerror = require('../../../kerror').wrap('network', 'http');
|
|
|
38
38
|
* in JSON format
|
|
39
39
|
*/
|
|
40
40
|
class RouteHandler {
|
|
41
|
-
constructor(url, query, message) {
|
|
41
|
+
constructor (url, query, message) {
|
|
42
42
|
this.handler = null;
|
|
43
43
|
this._request = null;
|
|
44
44
|
this.url = url;
|
|
@@ -92,7 +92,7 @@ class RouteHandler {
|
|
|
92
92
|
* @param {string} name
|
|
93
93
|
* @param {string} value
|
|
94
94
|
*/
|
|
95
|
-
addArgument(name, value) {
|
|
95
|
+
addArgument (name, value) {
|
|
96
96
|
this.data[name] = value;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -101,7 +101,7 @@ class RouteHandler {
|
|
|
101
101
|
*
|
|
102
102
|
* @param {Function} callback
|
|
103
103
|
*/
|
|
104
|
-
invokeHandler(callback) {
|
|
104
|
+
invokeHandler (callback) {
|
|
105
105
|
this.handler(this.request, callback);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -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,18 @@ const HTTP_ALLOWED_CONTENT_TYPES = [
|
|
|
76
77
|
'application/x-www-form-urlencoded',
|
|
77
78
|
'multipart/form-data',
|
|
78
79
|
];
|
|
80
|
+
const HTTP_SKIPPED_HEADERS = [
|
|
81
|
+
'content-length',
|
|
82
|
+
];
|
|
83
|
+
const HTTP_HEADER_CONNECTION = Buffer.from('Connection');
|
|
79
84
|
const HTTP_HEADER_CONTENT_LENGTH = Buffer.from('Content-Length');
|
|
80
85
|
const HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = Buffer.from('Access-Control-Allow-Origin');
|
|
81
86
|
const HTTP_HEADER_VARY = Buffer.from('Vary');
|
|
87
|
+
const HTTP_HEADER_TRANSFER_ENCODING = Buffer.from('Transfer-Encoding');
|
|
88
|
+
const CHUNKED = Buffer.from('chunked');
|
|
82
89
|
const WILDCARD = Buffer.from('*');
|
|
83
90
|
const ORIGIN = Buffer.from('Origin');
|
|
91
|
+
const CLOSE = Buffer.from('close');
|
|
84
92
|
const CHARSET_REGEX = /charset=([\w-]+)/i;
|
|
85
93
|
|
|
86
94
|
/**
|
|
@@ -119,7 +127,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
119
127
|
this.wsConfig = this.parseWebSocketOptions();
|
|
120
128
|
this.httpConfig = this.parseHttpOptions();
|
|
121
129
|
|
|
122
|
-
if (!this.wsConfig.enabled && !this.httpConfig.enabled) {
|
|
130
|
+
if (! this.wsConfig.enabled && ! this.httpConfig.enabled) {
|
|
123
131
|
return false;
|
|
124
132
|
}
|
|
125
133
|
|
|
@@ -135,7 +143,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
this.server.listen(entrypoint.config.port, socket => {
|
|
138
|
-
if (!socket) {
|
|
146
|
+
if (! socket) {
|
|
139
147
|
throw new Error(`[http/websocket] fatal: unable to listen to port ${entrypoint.config.port}`);
|
|
140
148
|
}
|
|
141
149
|
});
|
|
@@ -197,7 +205,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
197
205
|
const socket = this.socketByConnectionId.get(data.connectionId);
|
|
198
206
|
debugWS('notify: %a', data);
|
|
199
207
|
|
|
200
|
-
if (!socket) {
|
|
208
|
+
if (! socket) {
|
|
201
209
|
return;
|
|
202
210
|
}
|
|
203
211
|
|
|
@@ -212,7 +220,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
212
220
|
joinChannel (channel, connectionId) {
|
|
213
221
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
214
222
|
|
|
215
|
-
if (!socket) {
|
|
223
|
+
if (! socket) {
|
|
216
224
|
return;
|
|
217
225
|
}
|
|
218
226
|
|
|
@@ -223,7 +231,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
223
231
|
leaveChannel (channel, connectionId) {
|
|
224
232
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
225
233
|
|
|
226
|
-
if (!socket) {
|
|
234
|
+
if (! socket) {
|
|
227
235
|
return;
|
|
228
236
|
}
|
|
229
237
|
|
|
@@ -237,7 +245,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
237
245
|
|
|
238
246
|
const socket = this.socketByConnectionId.get(connectionId);
|
|
239
247
|
|
|
240
|
-
if (!socket) {
|
|
248
|
+
if (! socket) {
|
|
241
249
|
return;
|
|
242
250
|
}
|
|
243
251
|
|
|
@@ -260,7 +268,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
260
268
|
|
|
261
269
|
wsOnOpenHandler (socket) {
|
|
262
270
|
const ip = Buffer.from(socket.getRemoteAddressAsText()).toString();
|
|
263
|
-
const connection = new ClientConnection(this.name, [ip], {cookie: socket.cookie});
|
|
271
|
+
const connection = new ClientConnection(this.name, [ip], { cookie: socket.cookie });
|
|
264
272
|
|
|
265
273
|
this.entryPoint.newConnection(connection);
|
|
266
274
|
this.connectionBySocket.set(socket, connection);
|
|
@@ -271,7 +279,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
271
279
|
wsOnCloseHandler (socket, code, message) {
|
|
272
280
|
const connection = this.connectionBySocket.get(socket);
|
|
273
281
|
|
|
274
|
-
if (!connection) {
|
|
282
|
+
if (! connection) {
|
|
275
283
|
return;
|
|
276
284
|
}
|
|
277
285
|
|
|
@@ -289,7 +297,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
289
297
|
}
|
|
290
298
|
|
|
291
299
|
wsOnMessageHandler (socket, data) {
|
|
292
|
-
if (!data || data.byteLength === 0) {
|
|
300
|
+
if (! data || data.byteLength === 0) {
|
|
293
301
|
return;
|
|
294
302
|
}
|
|
295
303
|
|
|
@@ -346,7 +354,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
346
354
|
request = new Request(parsed, { connection });
|
|
347
355
|
}
|
|
348
356
|
catch (e) {
|
|
349
|
-
this.wsSendError(socket, connection, e);
|
|
357
|
+
this.wsSendError(socket, connection, e, parsed.requestId);
|
|
350
358
|
return;
|
|
351
359
|
}
|
|
352
360
|
|
|
@@ -387,9 +395,14 @@ class HttpWsProtocol extends Protocol {
|
|
|
387
395
|
* @param {uWS.WebSocket} socket
|
|
388
396
|
* @param {ClientConnection} connection
|
|
389
397
|
* @param {Error} error
|
|
398
|
+
* @param {String} requestId @optional
|
|
390
399
|
*/
|
|
391
|
-
wsSendError (socket, connection, error) {
|
|
400
|
+
wsSendError (socket, connection, error, requestId) {
|
|
392
401
|
const request = new Request({}, { connection, error });
|
|
402
|
+
|
|
403
|
+
// If a requestId is provided we use it instead of the generated one
|
|
404
|
+
request.id = requestId || request.id;
|
|
405
|
+
|
|
393
406
|
const sanitized = removeErrorStack(request.response.toJSON()).content;
|
|
394
407
|
|
|
395
408
|
this.wsSend(socket, Buffer.from(JSON.stringify(sanitized)));
|
|
@@ -403,7 +416,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
403
416
|
* @param {Buffer} payload
|
|
404
417
|
*/
|
|
405
418
|
wsSend (socket, payload) {
|
|
406
|
-
if (!this.connectionBySocket.has(socket)) {
|
|
419
|
+
if (! this.connectionBySocket.has(socket)) {
|
|
407
420
|
return;
|
|
408
421
|
}
|
|
409
422
|
|
|
@@ -442,7 +455,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
442
455
|
const contentType = message.headers['content-type'];
|
|
443
456
|
|
|
444
457
|
if ( contentType
|
|
445
|
-
&& !HTTP_ALLOWED_CONTENT_TYPES.some(allowed => contentType.includes(allowed))
|
|
458
|
+
&& ! HTTP_ALLOWED_CONTENT_TYPES.some(allowed => contentType.includes(allowed))
|
|
446
459
|
) {
|
|
447
460
|
this.httpSendError(
|
|
448
461
|
message,
|
|
@@ -499,7 +512,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
499
512
|
return;
|
|
500
513
|
}
|
|
501
514
|
|
|
502
|
-
if (!isLast) {
|
|
515
|
+
if (! isLast) {
|
|
503
516
|
return;
|
|
504
517
|
}
|
|
505
518
|
|
|
@@ -582,6 +595,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
582
595
|
return;
|
|
583
596
|
}
|
|
584
597
|
|
|
598
|
+
if (request.result instanceof HttpStream) {
|
|
599
|
+
this.httpSendStream(request, response, request.result, message);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Send the response in one go
|
|
604
|
+
|
|
585
605
|
const data = this.httpRequestToResponse(request, message);
|
|
586
606
|
|
|
587
607
|
this.httpCompress(message, data, result => {
|
|
@@ -592,36 +612,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
592
612
|
request.response.setHeader('Content-Encoding', result.encoding);
|
|
593
613
|
|
|
594
614
|
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
|
-
}
|
|
615
|
+
this.httpWriteRequestHeaders(request, response, message);
|
|
619
616
|
|
|
620
617
|
const [ success ] = response.tryEnd(
|
|
621
618
|
result.compressed,
|
|
622
619
|
result.compressed.length);
|
|
623
620
|
|
|
624
|
-
if (!success) {
|
|
621
|
+
if (! success) {
|
|
625
622
|
response.onWritable(offset => {
|
|
626
623
|
const retryData = result.compressed.subarray(offset);
|
|
627
624
|
const [ retrySuccess ] = response.tryEnd(
|
|
@@ -636,6 +633,182 @@ class HttpWsProtocol extends Protocol {
|
|
|
636
633
|
});
|
|
637
634
|
}
|
|
638
635
|
|
|
636
|
+
/**
|
|
637
|
+
*
|
|
638
|
+
* @param {uWS.HttpRequest} request
|
|
639
|
+
* @param {uWS.HttpResponse} response
|
|
640
|
+
* @param {HttpMessage} message
|
|
641
|
+
*/
|
|
642
|
+
httpWriteRequestHeaders (request, response, message) {
|
|
643
|
+
response.writeStatus(Buffer.from(request.response.status.toString()));
|
|
644
|
+
|
|
645
|
+
response.writeHeader(HTTP_HEADER_CONNECTION, CLOSE);
|
|
646
|
+
|
|
647
|
+
for (const header of this.httpConfig.headers) {
|
|
648
|
+
// If header is missing, add the default one
|
|
649
|
+
if (request.response.headers[header[2]] === undefined) {
|
|
650
|
+
response.writeHeader(header[0], header[1]);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Access-Control-Allow-Origin Logic
|
|
655
|
+
if ( request.response.headers['Access-Control-Allow-Origin'] === undefined
|
|
656
|
+
&& message.headers
|
|
657
|
+
&& message.headers.origin
|
|
658
|
+
) {
|
|
659
|
+
response.writeHeader(
|
|
660
|
+
HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
|
|
661
|
+
Buffer.from(message.headers.origin));
|
|
662
|
+
|
|
663
|
+
response.writeHeader(HTTP_HEADER_VARY, ORIGIN);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
for (const [key, value] of Object.entries(request.response.headers)) {
|
|
667
|
+
// Skip some headers that are not allowed to be sent or modified
|
|
668
|
+
if (HTTP_SKIPPED_HEADERS.includes(key.toLowerCase())) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
response.writeHeader(Buffer.from(key), Buffer.from(value.toString()));
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Send stream data thorugh the HTTP response
|
|
678
|
+
* @param {HttpRequest} request
|
|
679
|
+
* @param {HttpStream} httpStream - The data stream to send
|
|
680
|
+
* @param {uWS.HttpResponse} response
|
|
681
|
+
* @param {HttpMessage} message
|
|
682
|
+
*/
|
|
683
|
+
httpSendStream (request, response, httpStream, message) {
|
|
684
|
+
const streamSizeFixed = typeof httpStream.totalBytes === 'number' && httpStream.totalBytes > 0;
|
|
685
|
+
|
|
686
|
+
if (httpStream.errored) {
|
|
687
|
+
this.httpSendError(
|
|
688
|
+
message,
|
|
689
|
+
response,
|
|
690
|
+
kerror.get('network', 'http', 'stream_errored', httpStream.error.message)
|
|
691
|
+
);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (httpStream.destroyed) {
|
|
696
|
+
this.httpSendError(
|
|
697
|
+
message,
|
|
698
|
+
response,
|
|
699
|
+
kerror.get('network', 'http', 'stream_closed')
|
|
700
|
+
);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Remove Content-Length header to avoid conflic with Transfer-Encoding header
|
|
705
|
+
request.response.setHeader('Content-Length', null);
|
|
706
|
+
|
|
707
|
+
// Send Headers in one go
|
|
708
|
+
response.cork(() => {
|
|
709
|
+
this.httpWriteRequestHeaders(request, response, message);
|
|
710
|
+
|
|
711
|
+
if (streamSizeFixed) {
|
|
712
|
+
response.writeHeader(HTTP_HEADER_CONTENT_LENGTH, Buffer.from(httpStream.totalBytes.toString()));
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
response.writeHeader(HTTP_HEADER_TRANSFER_ENCODING, CHUNKED);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
httpStream.stream.on('data', chunk => {
|
|
720
|
+
// Make a copy of the array buffer
|
|
721
|
+
const arrayBuffer = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
|
|
722
|
+
|
|
723
|
+
const arrayBufferOffset = response.getWriteOffset();
|
|
724
|
+
|
|
725
|
+
let backpressure = false;
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Switch method of writing data to the response
|
|
729
|
+
* based on the size of the stream.
|
|
730
|
+
* If the stream has a fixed size we can use the tryEnd method
|
|
731
|
+
*/
|
|
732
|
+
if (streamSizeFixed) {
|
|
733
|
+
const [ success, done ] = response.tryEnd(arrayBuffer, httpStream.totalBytes);
|
|
734
|
+
backpressure = ! success;
|
|
735
|
+
|
|
736
|
+
if (done) {
|
|
737
|
+
httpStream.destroy();
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
const success = response.write(arrayBuffer);
|
|
743
|
+
|
|
744
|
+
backpressure = ! success;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// In case of backpressure we need to wait for drainage before sending more data
|
|
748
|
+
if (backpressure) {
|
|
749
|
+
response.arrayBufferOffset = arrayBufferOffset;
|
|
750
|
+
response.arrayBuffer = arrayBuffer;
|
|
751
|
+
httpStream.stream.pause();
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* When the stream is drained we can resume sending data,
|
|
755
|
+
* only if the is no backpressure after we wrote the missing chunk data.
|
|
756
|
+
*/
|
|
757
|
+
response.onWritable(offset => {
|
|
758
|
+
if (! streamSizeFixed && offset - response.arrayBufferOffset === 0) {
|
|
759
|
+
httpStream.stream.resume();
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
let retryBackpressure = false;
|
|
764
|
+
const remainingChunkData = response.arrayBuffer.slice(offset - response.arrayBufferOffset);
|
|
765
|
+
|
|
766
|
+
if (streamSizeFixed) {
|
|
767
|
+
const [ success ] = response.tryEnd(remainingChunkData, httpStream.totalBytes);
|
|
768
|
+
|
|
769
|
+
retryBackpressure = ! success;
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
const success = response.write(remainingChunkData);
|
|
773
|
+
|
|
774
|
+
retryBackpressure = ! success;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (! retryBackpressure) {
|
|
778
|
+
httpStream.stream.resume();
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return ! retryBackpressure;
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
httpStream.stream.on('end', () => {
|
|
787
|
+
if (httpStream.destroy()) {
|
|
788
|
+
response.end();
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
httpStream.stream.on('close', () => {
|
|
793
|
+
if (httpStream.destroy()) {
|
|
794
|
+
response.end();
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
httpStream.stream.on('error', err => {
|
|
799
|
+
if (httpStream.destroy()) {
|
|
800
|
+
response.end();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
debugHTTP('[%s] httpSendStream: %s', httpStream.connection.id, err.message);
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
response.onAborted(() => {
|
|
807
|
+
httpStream.destroy();
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
}
|
|
811
|
+
|
|
639
812
|
/**
|
|
640
813
|
* Forward an error response to the client
|
|
641
814
|
*
|
|
@@ -676,7 +849,8 @@ class HttpWsProtocol extends Protocol {
|
|
|
676
849
|
if (message.headers && message.headers.origin) {
|
|
677
850
|
if (global.kuzzle.config.internal.allowAllOrigins) {
|
|
678
851
|
response.writeHeader(HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, WILDCARD);
|
|
679
|
-
}
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
680
854
|
response.writeHeader(HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, Buffer.from(message.headers.origin));
|
|
681
855
|
response.writeHeader(HTTP_HEADER_VARY, ORIGIN);
|
|
682
856
|
}
|
|
@@ -699,13 +873,13 @@ class HttpWsProtocol extends Protocol {
|
|
|
699
873
|
* @param {HttpMessage} message
|
|
700
874
|
* @returns {Buffer}
|
|
701
875
|
*/
|
|
702
|
-
httpRequestToResponse(request, message) {
|
|
876
|
+
httpRequestToResponse (request, message) {
|
|
703
877
|
let data = removeErrorStack(request.response.toJSON());
|
|
704
878
|
|
|
705
879
|
if (message.requestId !== data.requestId) {
|
|
706
880
|
data.requestId = message.requestId;
|
|
707
881
|
|
|
708
|
-
if (!data.raw) {
|
|
882
|
+
if (! data.raw) {
|
|
709
883
|
data.content.requestId = message.requestId;
|
|
710
884
|
}
|
|
711
885
|
}
|
|
@@ -759,7 +933,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
759
933
|
* @param {Buffer} data
|
|
760
934
|
* @param {Function} callback
|
|
761
935
|
*/
|
|
762
|
-
httpCompress(message, data, callback) {
|
|
936
|
+
httpCompress (message, data, callback) {
|
|
763
937
|
if (message.headers['accept-encoding']) {
|
|
764
938
|
const encodings = message.headers['accept-encoding']
|
|
765
939
|
.split(',')
|
|
@@ -788,15 +962,15 @@ class HttpWsProtocol extends Protocol {
|
|
|
788
962
|
|
|
789
963
|
if (algorithm === 'gzip') {
|
|
790
964
|
zlib.gzip(data, (err, compressed) => callback({
|
|
791
|
-
compressed: !err ? compressed : data,
|
|
792
|
-
encoding: !err ? 'gzip' : 'identity',
|
|
965
|
+
compressed: ! err ? compressed : data,
|
|
966
|
+
encoding: ! err ? 'gzip' : 'identity',
|
|
793
967
|
}));
|
|
794
968
|
return;
|
|
795
969
|
}
|
|
796
970
|
else if (algorithm === 'deflate') {
|
|
797
971
|
zlib.deflate(data, (err, compressed) => callback({
|
|
798
|
-
compressed: !err ? compressed : data,
|
|
799
|
-
encoding: !err ? 'deflate' : 'identity',
|
|
972
|
+
compressed: ! err ? compressed : data,
|
|
973
|
+
encoding: ! err ? 'deflate' : 'identity',
|
|
800
974
|
}));
|
|
801
975
|
return;
|
|
802
976
|
}
|
|
@@ -810,7 +984,7 @@ class HttpWsProtocol extends Protocol {
|
|
|
810
984
|
|
|
811
985
|
httpUncompress (message, payload, cb) {
|
|
812
986
|
let encodings = message.headers['content-encoding'];
|
|
813
|
-
if (!encodings) {
|
|
987
|
+
if (! encodings) {
|
|
814
988
|
cb(null, payload);
|
|
815
989
|
return;
|
|
816
990
|
}
|
|
@@ -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
|
|