soajs.controller 4.2.36 → 4.2.38

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/header.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * @license
5
+ * Copyright SOAJS All Rights Reserved.
6
+ *
7
+ * Use of this source code is governed by an Apache license that can be
8
+ * found in the LICENSE file at the root of this repository
9
+ */
10
+
11
+
12
+ /**
13
+ * Encodes a string to be safely used as an HTTP header value.
14
+ * This preserves all data and is the standard, recommended method.
15
+ *
16
+ * @param {string | number | boolean} value The value to encode.
17
+ * @returns {string} The URL-encoded string.
18
+ */
19
+ function encodeHeaderValue(value) {
20
+ if (value === null || typeof value === 'undefined') {
21
+ return '';
22
+ }
23
+ return encodeURIComponent(String(value));
24
+ }
25
+
26
+ /**
27
+ * Decodes a URL-encoded string from an HTTP header.
28
+ * It safely handles potential errors if the input is malformed.
29
+ *
30
+ * @param {string} encodedValue The percent-encoded header value to decode.
31
+ * @returns {string} The decoded (original) string, or the original
32
+ * string if decoding fails.
33
+ */
34
+ function decodeHeaderValue(encodedValue) {
35
+ // Return empty string or null as is, to avoid errors.
36
+ if (!encodedValue) {
37
+ return encodedValue;
38
+ }
39
+
40
+ try {
41
+ // The standard way to decode a value encoded by encodeURIComponent.
42
+ return decodeURIComponent(encodedValue);
43
+ } catch (e) {
44
+ // This catches errors from malformed URI sequences (e.g., a lone '%').
45
+ console.error(`Failed to decode header value: "${encodedValue}"`, e);
46
+ // Return the original, undecoded value so the app doesn't crash.
47
+ return encodedValue;
48
+ }
49
+ }
50
+
51
+ module.exports = { encodeHeaderValue, decodeHeaderValue };
package/lib/request.js CHANGED
@@ -18,6 +18,7 @@ function checkStatus(uri) {
18
18
  const req = http.get(uri, (res) => {
19
19
  if (res.statusCode === 200) {
20
20
  onResponse = true;
21
+ res.resume();
21
22
  resolve(res.statusCode === 200); // Resolve with true if 200, false otherwise
22
23
  }
23
24
  // res.on('data', () => { }); // Consume data to avoid issues (important!)
@@ -28,12 +29,12 @@ function checkStatus(uri) {
28
29
  return reject(err);
29
30
  }
30
31
  });
31
- res.on('close', () => {
32
- if (!onResponse) {
33
- onResponse = true;
34
- return reject(new Error("Closed"));
35
- }
36
- });
32
+ // res.on('close', () => {
33
+ // if (!onResponse) {
34
+ // onResponse = true;
35
+ // return reject(new Error("Closed"));
36
+ // }
37
+ // });
37
38
  });
38
39
 
39
40
  req.on('error', (err) => {
@@ -42,19 +43,26 @@ function checkStatus(uri) {
42
43
  return reject(err);
43
44
  }
44
45
  });
45
- req.on('close', () => {
46
+ // req.on('close', () => {
47
+ // if (!onResponse) {
48
+ // onResponse = true;
49
+ // return reject(new Error("Closed"));
50
+ // }
51
+ // });
52
+
53
+ req.setTimeout(5000, () => {
54
+ req.destroy();
46
55
  if (!onResponse) {
47
56
  onResponse = true;
48
- return reject(new Error("Closed"));
57
+ return reject(new Error('Request timed out'));
49
58
  }
50
59
  });
51
60
 
52
-
53
61
  req.end();
54
62
  });
55
63
  }
56
64
 
57
- function httpRequestLight({ uri, data = null, method = 'GET', headers = null, json = true }) {
65
+ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, json = true, timeout = 8000 }) {
58
66
  return new Promise((resolve, reject) => {
59
67
  let onResponse = false;
60
68
  let options = {};
@@ -96,6 +104,8 @@ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, js
96
104
 
97
105
  req.on('response', (res) => { // Listen for the 'response' event
98
106
  if (res.statusCode < 200 || res.statusCode >= 300) {
107
+ onResponse = true;
108
+ res.resume();
99
109
  return reject(new Error(`Status Code: ${res.statusCode}`));
100
110
  }
101
111
 
@@ -106,7 +116,6 @@ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, js
106
116
  });
107
117
 
108
118
  res.on('end', () => {
109
-
110
119
  if (!onResponse) {
111
120
  onResponse = true;
112
121
  try {
@@ -145,6 +154,17 @@ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, js
145
154
  }
146
155
  });
147
156
 
157
+ // Handle request timeout
158
+ req.on('timeout', () => {
159
+ req.destroy(); // IMPORTANT: Forcefully end the request
160
+ if (!onResponse) {
161
+ onResponse = true;
162
+ return reject(new Error('Request timed out'));
163
+ }
164
+ });
165
+ // Set the timeout on the request
166
+ req.setTimeout(timeout);
167
+
148
168
  if (data) {
149
169
  req.write(requestDataString);
150
170
  }
@@ -153,7 +173,7 @@ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, js
153
173
  });
154
174
  }
155
175
 
156
- function httpRequest({ uri, data = null, body = null, qs = null, method = 'GET', headers = null, json = true }) {
176
+ function httpRequest({ uri, data = null, body = null, qs = null, method = 'GET', headers = null, json = true, timeout = 8000 }) {
157
177
  return new Promise((resolve, reject) => {
158
178
  data = data || body; // to be compatible with request package
159
179
 
@@ -270,6 +290,17 @@ function httpRequest({ uri, data = null, body = null, qs = null, method = 'GET',
270
290
  }
271
291
  });
272
292
 
293
+ // Handle request timeout
294
+ req.on('timeout', () => {
295
+ req.destroy(); // IMPORTANT: Forcefully end the request
296
+ if (!onResponse) {
297
+ onResponse = true;
298
+ return reject(new Error('Request timed out'));
299
+ }
300
+ });
301
+ // Set the timeout on the request
302
+ req.setTimeout(timeout);
303
+
273
304
  if (data) {
274
305
  req.write(requestDataString);
275
306
  }
@@ -288,7 +319,7 @@ function proxyRequest(req, res, options, extraOptions = {}) {
288
319
  } else {
289
320
  proxyReq = http.request(options);
290
321
  }
291
-
322
+
292
323
  if (extraOptions && extraOptions.fetchProxReq) {
293
324
  extraOptions.fetchProxReq(proxyReq);
294
325
  }
@@ -79,10 +79,10 @@ module.exports = (configuration) => {
79
79
  .then(() => { })
80
80
  .catch((error) => {
81
81
  req.soajs.log.error(error.message);
82
- // if (req.soajs.controller.redirectedRequest) {
83
- // req.soajs.controller.redirectedRequest.destroy();
84
- // req.soajs.controller.redirectedRequest = null;
85
- // }
82
+ if (req.soajs.controller.redirectedRequest) {
83
+ req.soajs.controller.redirectedRequest.destroy();
84
+ req.soajs.controller.redirectedRequest = null;
85
+ }
86
86
  return req.soajs.controllerResponse(core.error.getError(135));
87
87
  });
88
88
  };
@@ -220,10 +220,10 @@ module.exports = (configuration) => {
220
220
  })
221
221
  .catch((err) => {
222
222
  req.soajs.log.error(err.message + ' with [' + restServiceParams.name + (restServiceParams.version ? ('@' + restServiceParams.version) : '') + ']');
223
- // if (req.soajs.controller.redirectedRequest) {
224
- // req.soajs.controller.redirectedRequest.destroy();
225
- // req.soajs.controller.redirectedRequest = null;
226
- // }
223
+ if (req.soajs.controller.redirectedRequest) {
224
+ req.soajs.controller.redirectedRequest.destroy();
225
+ req.soajs.controller.redirectedRequest = null;
226
+ }
227
227
  if (!req.soajs.controller.monitorEndingReq) {
228
228
  req.soajs.controllerResponse(core.error.getError(135));
229
229
  }
@@ -60,10 +60,10 @@ module.exports = (configuration) => {
60
60
  })
61
61
  .catch((err) => {
62
62
  req.soajs.log.error(err.code, err.message);
63
- // if (req.soajs.controller.redirectedRequest) {
64
- // req.soajs.controller.redirectedRequest.destroy();
65
- // req.soajs.controller.redirectedRequest = null;
66
- // }
63
+ if (req.soajs.controller.redirectedRequest) {
64
+ req.soajs.controller.redirectedRequest.destroy();
65
+ req.soajs.controller.redirectedRequest = null;
66
+ }
67
67
  if (!req.soajs.controller.monitorEndingReq) {
68
68
  return req.soajs.controllerResponse(core.error.getError(135));
69
69
  }
package/mw/mt/index.js CHANGED
@@ -12,6 +12,9 @@ const async = require("async");
12
12
 
13
13
  const utils = require("./utils");
14
14
 
15
+
16
+ const { encodeHeaderValue } = require("../../lib/header.js");
17
+
15
18
  /**
16
19
  *
17
20
  * @param configuration
@@ -247,8 +250,8 @@ module.exports = (configuration) => {
247
250
  injectObj.urac = {
248
251
  "_id": uracObj._id,
249
252
  "username": uracObj.username,
250
- "firstName": uracObj.firstName,
251
- "lastName": uracObj.lastName,
253
+ "firstName": encodeHeaderValue(uracObj.firstName),
254
+ "lastName": encodeHeaderValue(uracObj.lastName),
252
255
  "email": uracObj.email,
253
256
  "groups": uracObj.groups,
254
257
  "socialLogin": uracObj.socialLogin,
@@ -336,12 +339,14 @@ module.exports = (configuration) => {
336
339
  req.soajs.log.error(err.message);
337
340
  }
338
341
  let _h = JSON.stringify(injectObj);
339
- req.headers.soajsinjectobj = Buffer.from(_h, 'ascii').toString('utf-8');
342
+ // req.headers.soajsinjectobj = Buffer.from(_h, 'ascii').toString('utf-8');
343
+ req.headers.soajsinjectobj = _h; //encodeHeaderValue(_h);
340
344
  return next();
341
345
  });
342
346
  } else {
343
347
  let _h = JSON.stringify(injectObj);
344
- req.headers.soajsinjectobj = Buffer.from(_h, 'ascii').toString('utf-8');
348
+ // req.headers.soajsinjectobj = Buffer.from(_h, 'ascii').toString('utf-8');
349
+ req.headers.soajsinjectobj = _h; //encodeHeaderValue(_h);
345
350
  return next();
346
351
  }
347
352
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "soajs.controller",
3
3
  "description": "soajs multi tenant API gateway",
4
- "version": "4.2.36",
4
+ "version": "4.2.38",
5
5
  "author": {
6
6
  "name": "soajs team",
7
7
  "email": "team@soajs.org"
@@ -27,7 +27,7 @@ let service = {
27
27
  },
28
28
  oauth: true,
29
29
  extKeyRequired: true,
30
- urac: false,
30
+ urac: true,
31
31
  urac_Profile: false,
32
32
  urac_ACL: false,
33
33
  provision_ACL: false,
@@ -9,7 +9,7 @@ let token = {
9
9
  _id: "5c8d0c505653de3985aa0ffd",
10
10
  locked: true,
11
11
  username: "owner",
12
- firstName: "owner3",
12
+ firstName: "owner3'sèį",
13
13
  lastName: "owner",
14
14
  email: "me@localhost.com",
15
15
  "ts": new Date().getTime(),
@@ -9,7 +9,7 @@ let token = {
9
9
  _id: "5c8d0c505653de3985aa0ffd",
10
10
  locked: true,
11
11
  username: "owner",
12
- firstName: "owner3",
12
+ firstName: "owner3'sèį",
13
13
  lastName: "owner",
14
14
  email: "me@localhost.com",
15
15
  "ts": new Date().getTime(),
@@ -4,7 +4,7 @@ let user = {
4
4
  locked: true,
5
5
  username: "owner",
6
6
  password: "$2a$12$geJJfv33wkYIXEAlDkeeuOgiQ6y6MjP/YxbqLdHdDSK7LDG.7n7Pq",
7
- firstName: "owner3",
7
+ firstName: "owner3'sèį",
8
8
  lastName: "owner",
9
9
  email: "me@localhost.com",
10
10
  ts: 1552747600152,
@@ -20,15 +20,17 @@ function startServer(serverConfig, callback) {
20
20
  'lastname': "hage"
21
21
  }
22
22
  };
23
-
24
-
25
- sApp.get('/passport/login', (req, res) => res.json(sReply));
26
-
23
+
24
+
25
+ sApp.get('/passport/login', (req, res) => {
26
+ res.json(sReply);
27
+ });
28
+
27
29
  mApp.get('/heartbeat', (req, res) => res.json(mReply));
28
-
30
+
29
31
  let sAppServer = sApp.listen(serverConfig.s.port, () => console.log(`${serverConfig.name} service mock listening on port ${serverConfig.s.port}!`));
30
32
  let mAppServer = mApp.listen(serverConfig.m.port, () => console.log(`${serverConfig.name} service mock listening on port ${serverConfig.m.port}!`));
31
-
33
+
32
34
  return callback(
33
35
  {
34
36
  "sAppServer": sAppServer,
@@ -40,11 +42,11 @@ function startServer(serverConfig, callback) {
40
42
 
41
43
  function killServer(config) {
42
44
  console.log("killing server ....");
43
-
45
+
44
46
  config.mAppServer.close((err) => {
45
47
  console.log("...sAppServer: " + config.name);
46
48
  });
47
-
49
+
48
50
  config.sAppServer.close((err) => {
49
51
  console.log("...mAppServer: " + config.name);
50
52
  });
@@ -44,7 +44,7 @@
44
44
  "requestTimeoutRenewal": 5,
45
45
  "extKeyRequired": true,
46
46
  "oauth": true,
47
- "urac": false,
47
+ "urac": true,
48
48
  "urac_Profile": false,
49
49
  "urac_ACL": false,
50
50
  "tenant_Profile": false,