alchemymvc 1.3.17 → 1.3.18

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.
@@ -125,12 +125,23 @@ Conduit.setProperty(function scene() {
125
125
  return this.getSession().getScene(this.scene_id);
126
126
  });
127
127
 
128
+ /**
129
+ * The session cookie name to use
130
+ *
131
+ * @author Jelle De Loecker <jelle@elevenways.be>
132
+ * @since 1.3.18
133
+ * @version 1.3.18
134
+ */
135
+ Conduit.setProperty(function session_cookie_name() {
136
+ return alchemy.settings.session_key || 'alchemy_sid';
137
+ });
138
+
128
139
  /**
129
140
  * Enforce the scene_id
130
141
  *
131
142
  * @author Jelle De Loecker <jelle@elevenways.be>
132
143
  * @since 1.1.0
133
- * @version 1.3.10
144
+ * @version 1.3.18
134
145
  */
135
146
  Conduit.enforceProperty(function scene_id(new_value, old_value) {
136
147
 
@@ -160,7 +171,10 @@ Conduit.enforceProperty(function scene_id(new_value, old_value) {
160
171
  path: path,
161
172
 
162
173
  // Cookie should not live for more than 15 seconds
163
- maxAge: 1000 * 15
174
+ maxAge: 1000 * 15,
175
+
176
+ // It should be restricted to the same domain
177
+ domain: false,
164
178
  });
165
179
  }
166
180
  }
@@ -259,12 +273,17 @@ Conduit.setProperty(function is_secure() {
259
273
  *
260
274
  * @author Jelle De Loecker <jelle@develry.be>
261
275
  * @since 1.1.0
262
- * @version 1.1.0
276
+ * @version 1.3.18
263
277
  *
264
- * @param {Object}
278
+ * @param {Object|String}
265
279
  */
266
280
  Conduit.setMethod(function setRequestBody(body) {
267
281
 
282
+ if (typeof body == 'string') {
283
+ this.body = body;
284
+ return;
285
+ }
286
+
268
287
  if (!body) {
269
288
  return;
270
289
  }
@@ -492,20 +511,18 @@ Conduit.setMethod(function time() {
492
511
  *
493
512
  * @author Jelle De Loecker <jelle@elevenways.be>
494
513
  * @since 0.2.0
495
- * @version 1.3.17
514
+ * @version 1.3.18
496
515
  *
497
516
  * @param {IncomingMessage} req
498
517
  * @param {ServerResponse} res
499
518
  */
500
519
  Conduit.setMethod(async function parseRequest() {
501
520
 
502
- var protocol,
503
- section;
504
-
505
521
  if (this.method == null && this.request && this.request.method) {
506
522
  this.method = this.request.method.toLowerCase();
507
523
  }
508
524
 
525
+ this.parseUrl();
509
526
  this.parseShortcuts();
510
527
  this.parseLanguages();
511
528
  this.parsePrefix();
@@ -529,11 +546,25 @@ Conduit.setMethod(async function parseRequest() {
529
546
  this.overrideResponseUrl(new_url);
530
547
  }
531
548
 
549
+ this.parseUrl();
550
+ });
551
+
552
+ /**
553
+ * Parse the url if it hasn't been done already
554
+ *
555
+ * @author Jelle De Loecker <jelle@elevenways.be>
556
+ * @since 1.3.18
557
+ * @version 1.3.18
558
+ */
559
+ Conduit.setMethod(function parseUrl() {
560
+
532
561
  // If the url has already been parsed, return early
533
562
  if (this.url) {
534
- return;
563
+ return false;
535
564
  }
536
565
 
566
+ let protocol;
567
+
537
568
  if (alchemy.settings.assume_https) {
538
569
  protocol = 'https://';
539
570
  } else if (this.headers['x-forwarded-proto']) {
@@ -557,10 +588,10 @@ Conduit.setMethod(async function parseRequest() {
557
588
 
558
589
  // If no URL was set, use the first requests URL (without the path)
559
590
  if (!alchemy.settings.url && this.headers.host) {
560
- alchemy.settings.url = this.url+'';
591
+ alchemy.setUrl(this.url);
561
592
  }
562
593
 
563
- let path = this.path;
594
+ let path = this.original_path;
564
595
 
565
596
  if (this.prefix) {
566
597
  path = '/' + this.prefix + '/' + path;
@@ -2290,7 +2321,7 @@ Conduit.setMethod(function _sendStream(stream, options) {
2290
2321
  *
2291
2322
  * @author Jelle De Loecker <jelle@elevenways.be>
2292
2323
  * @since 0.2.0
2293
- * @version 1.3.6
2324
+ * @version 1.3.18
2294
2325
  *
2295
2326
  * @param {Boolean} create Create a session if none exist
2296
2327
  *
@@ -2303,13 +2334,10 @@ Conduit.setMethod(function getSession(allow_create = true) {
2303
2334
  return this.sessionData;
2304
2335
  }
2305
2336
 
2306
- let cookie_name,
2337
+ let cookie_name = this.session_cookie_name,
2307
2338
  session_id,
2308
2339
  session;
2309
2340
 
2310
- // Set the name of the cookie (could change in the future)
2311
- cookie_name = alchemy.settings.session_key || 'alchemy_sid';
2312
-
2313
2341
  // Get the ID of the session
2314
2342
  session_id = this.cookie(cookie_name);
2315
2343
 
@@ -2473,9 +2501,9 @@ Conduit.setMethod(function setRouteParameters(data) {
2473
2501
  /**
2474
2502
  * Get/set a cookie
2475
2503
  *
2476
- * @author Jelle De Loecker <jelle@develry.be>
2504
+ * @author Jelle De Loecker <jelle@elevenways.be>
2477
2505
  * @since 0.2.0
2478
- * @version 0.4.2
2506
+ * @version 1.3.18
2479
2507
  *
2480
2508
  * @param {String} name
2481
2509
  * @param {Mixed} value
@@ -2483,10 +2511,6 @@ Conduit.setMethod(function setRouteParameters(data) {
2483
2511
  */
2484
2512
  Conduit.setMethod(function cookie(name, value, options) {
2485
2513
 
2486
- var header,
2487
- arr,
2488
- key;
2489
-
2490
2514
  // Return if cookies are disabled
2491
2515
  if (!alchemy.settings.cookies) {
2492
2516
  return;
@@ -2517,12 +2541,34 @@ Conduit.setMethod(function cookie(name, value, options) {
2517
2541
  // Store it in the new_cookies object, for quick access
2518
2542
  this.new_cookies[name] = value;
2519
2543
 
2544
+ // If there is no domain set, see if it is required
2545
+ if ((options.domain === true || options.domain == null) && alchemy.settings.cookie_domain && this.url) {
2546
+ let wanted_domain = alchemy.settings.cookie_domain,
2547
+ actual_domain = this.url.hostname;
2548
+
2549
+ if (wanted_domain != actual_domain) {
2550
+ // You can only set a cookie on the current domain,
2551
+ // or a parent domain. But not on a child domain.
2552
+ if (wanted_domain.length < actual_domain.length && actual_domain.endsWith(wanted_domain)) {
2553
+ // It's allowed!
2554
+ } else {
2555
+ // When on a domain like "11ways.be" you
2556
+ // can not set a cookie for "www.11ways.be"
2557
+ wanted_domain = false;
2558
+ }
2559
+ }
2560
+
2561
+ if (wanted_domain) {
2562
+ options.domain = wanted_domain;
2563
+ }
2564
+ }
2565
+
2520
2566
  if (this.websocket) {
2521
2567
  return this.socket.emit('alchemy-set-cookie', {name: name, value: value, options: options});
2522
2568
  }
2523
2569
 
2524
2570
  // Create the basic header string
2525
- header = String.encodeCookie(name, value, options);
2571
+ let header = String.encodeCookie(name, value, options);
2526
2572
 
2527
2573
  // Add this to the cookieheader array
2528
2574
  this.new_cookie_header.push(header);
@@ -338,7 +338,7 @@ Alchemy.setMethod(function isTooBusyForRequests() {
338
338
  *
339
339
  * @author Jelle De Loecker <jelle@elevenways.be>
340
340
  * @since 1.3.1
341
- * @version 1.3.2
341
+ * @version 1.3.18
342
342
  *
343
343
  * @return {Boolean}
344
344
  */
@@ -348,11 +348,11 @@ Alchemy.setMethod(function isTooBusyForAjax() {
348
348
  return false;
349
349
  }
350
350
 
351
- let lag = this.lagInMs();
352
-
353
- let max_event_loop_lag = alchemy.settings.max_event_loop_lag || alchemy.settings.toobusy;
351
+ let max_event_loop_lag = alchemy.settings.max_event_loop_lag ?? alchemy.settings.toobusy;
354
352
 
355
353
  if (max_event_loop_lag) {
354
+ let lag = this.lagInMs();
355
+
356
356
  if (lag > (max_event_loop_lag * 3)) {
357
357
  return true;
358
358
  }
@@ -361,6 +361,28 @@ Alchemy.setMethod(function isTooBusyForAjax() {
361
361
  return false;
362
362
  });
363
363
 
364
+ /**
365
+ * Set the maximum event loop lag before the server is considered overloaded
366
+ *
367
+ * @author Jelle De Loecker <jelle@elevenways.be>
368
+ * @since 1.3.18
369
+ * @version 1.3.18
370
+ *
371
+ * @param {Number} max_lag
372
+ */
373
+ Alchemy.setMethod(function setMaxEventLoopLag(max_lag) {
374
+
375
+ if (typeof max_lag != 'number' || !isFinite(max_lag)) {
376
+ max_lag = null;
377
+ }
378
+
379
+ if (max_lag == null) {
380
+ max_lag = 70;
381
+ }
382
+
383
+ this.settings.max_event_loop_lag = max_lag;
384
+ });
385
+
364
386
  /**
365
387
  * Called after the server has started
366
388
  *
@@ -588,7 +610,7 @@ Alchemy.setMethod(function printLog(level, args, options) {
588
610
  *
589
611
  * @author Jelle De Loecker <jelle@develry.be>
590
612
  * @since 0.4.0
591
- * @version 1.3.3
613
+ * @version 1.3.18
592
614
  */
593
615
  Alchemy.setMethod(function loadSettings() {
594
616
 
@@ -726,8 +748,10 @@ Alchemy.setMethod(function loadSettings() {
726
748
  settings.url = this.argv.url;
727
749
  }
728
750
 
729
- if (settings.url && settings.url.indexOf('{') > -1) {
730
- settings.url = settings.url.assign(settings);
751
+ this.setUrl(settings.url);
752
+
753
+ if (settings.cookie_domain) {
754
+ this.setCookieDomain(settings.cookie_domain);
731
755
  }
732
756
 
733
757
  if (this.argv.preload) {
@@ -780,10 +804,76 @@ Alchemy.setMethod(function loadSettings() {
780
804
  this.doPreload();
781
805
  }
782
806
 
807
+ this.setMaxEventLoopLag(settings.max_event_loop_lag);
808
+
783
809
  // Set the debug value
784
810
  global.DEBUG = settings.debug;
785
811
  });
786
812
 
813
+ /**
814
+ * Set the main url
815
+ *
816
+ * @author Jelle De Loecker <jelle@elevenways.be>
817
+ * @since 1.3.18
818
+ * @version 1.3.18
819
+ *
820
+ * @param {RURL|String} value
821
+ */
822
+ Alchemy.setMethod(function setUrl(value) {
823
+
824
+ if (value) {
825
+ value = ''+value;
826
+
827
+ if (value.indexOf('{') > -1) {
828
+ value = value.assign(this.settings);
829
+ }
830
+ }
831
+
832
+ this.settings.url = value;
833
+
834
+ if (this.settings.cookie_domain === true || this.settings.cookie_domain == null) {
835
+ this.setCookieDomain(value);
836
+ }
837
+ });
838
+
839
+ /**
840
+ * Set the cookie domain
841
+ *
842
+ * @author Jelle De Loecker <jelle@elevenways.be>
843
+ * @since 1.3.18
844
+ * @version 1.3.18
845
+ *
846
+ * @param {RURL|String} value
847
+ */
848
+ Alchemy.setMethod(function setCookieDomain(value) {
849
+
850
+ if (value === false) {
851
+ this.settings.cookie_domain = false;
852
+ return;
853
+ }
854
+
855
+ if (!value) {
856
+ value = this.settings.url;
857
+ }
858
+
859
+ if (!value) {
860
+ return;
861
+ }
862
+
863
+ value = ''+value;
864
+
865
+ if (value.indexOf('{') > -1) {
866
+ value = value.assign(this.settings);
867
+ }
868
+
869
+ if (value.indexOf('/') > -1) {
870
+ let url = RURL.parse(value);
871
+ value = url.hostname;
872
+ }
873
+
874
+ this.settings.cookie_domain = value;
875
+ });
876
+
787
877
  /**
788
878
  * Set status
789
879
  *
@@ -1651,7 +1741,7 @@ Alchemy.setMethod(function addAppcacheEntry(entry) {
1651
1741
  *
1652
1742
  * @author Jelle De Loecker <jelle@develry.be>
1653
1743
  * @since 1.1.0
1654
- * @version 1.3.0
1744
+ * @version 1.3.18
1655
1745
  *
1656
1746
  * @param {IncomingMessage} req
1657
1747
  * @param {OutgoingMessage} res Optional
@@ -1674,8 +1764,10 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1674
1764
  return callback(null, req.body);
1675
1765
  }
1676
1766
 
1767
+ let content_type = req.headers['content-type'];
1768
+
1677
1769
  // Multipart data is handled by "formidable"
1678
- if (req.headers['content-type'] && req.headers['content-type'].startsWith('multipart/form-data')) {
1770
+ if (content_type && content_type.startsWith('multipart/form-data')) {
1679
1771
 
1680
1772
  let form = new formidable.IncomingForm({
1681
1773
  multiples : true,
@@ -1729,7 +1821,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1729
1821
  }
1730
1822
 
1731
1823
  // Regular form-encoded data
1732
- if (req.headers['content-type'] && req.headers['content-type'].indexOf('form-urlencoded') > -1) {
1824
+ if (content_type && content_type.indexOf('form-urlencoded') > -1) {
1733
1825
 
1734
1826
  urlFormBody(req, res, function parsedBody(err) {
1735
1827
 
@@ -1760,25 +1852,36 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1760
1852
  // Any other encoded data (like JSON)
1761
1853
  anyBody(req, function parsedBody(err, body) {
1762
1854
 
1763
- if (err && req.conduit && req.conduit.aborted) {
1764
- return callback(null);
1855
+ function handleResponse(err, body) {
1856
+ if (err && req.conduit && req.conduit.aborted) {
1857
+ return callback(null);
1858
+ }
1859
+
1860
+ // You can't send files using a regular post
1861
+ req.files = {};
1862
+
1863
+ if (err) {
1864
+ log.error('Error parsing body data', {err: err});
1865
+ req.body = {};
1866
+ } else {
1867
+ req.body = body;
1868
+
1869
+ if (conduit) {
1870
+ conduit.setRequestBody(body);
1871
+ }
1872
+ }
1873
+
1874
+ callback(null, req.body);
1765
1875
  }
1766
1876
 
1767
- // You can't send files using a regular post
1768
- req.files = {};
1769
-
1770
- if (err) {
1771
- log.error('Error parsing body data', {err: err});
1772
- req.body = {};
1773
- } else {
1774
- req.body = body;
1775
-
1776
- if (conduit) {
1777
- conduit.setRequestBody(body);
1877
+ if (err?.type == 'invalid.content.type') {
1878
+ if (!content_type || content_type.startsWith('text/')) {
1879
+ textBody(req, handleResponse);
1880
+ return;
1778
1881
  }
1779
1882
  }
1780
1883
 
1781
- callback(null, req.body);
1884
+ handleResponse(err, body);
1782
1885
  });
1783
1886
  });
1784
1887
 
@@ -2258,6 +2361,7 @@ log.todo = function todo(...args) {
2258
2361
 
2259
2362
  const anyBody = alchemy.use('body/any'),
2260
2363
  formBody = alchemy.use('body/form'),
2364
+ textBody = alchemy.use('body'),
2261
2365
  formidable = alchemy.use('formidable'),
2262
2366
  bodyParser = alchemy.use('body-parser'),
2263
2367
  urlFormBody = bodyParser.urlencoded({extended: true});
@@ -57,13 +57,6 @@ alchemy.hawkejs = Classes.Hawkejs.Hawkejs.getInstance();
57
57
  */
58
58
  alchemy.toobusy = alchemy.use('toobusy-js', 'toobusy');
59
59
 
60
- let max_event_loop_lag = alchemy.settings.max_event_loop_lag || alchemy.settings.toobusy;
61
-
62
- // If the config is a number, use that as the lag threshold
63
- if (typeof max_event_loop_lag === 'number') {
64
- alchemy.toobusy.maxLag(max_event_loop_lag);
65
- }
66
-
67
60
  /**
68
61
  * Load Sputnik, the stage-based launcher
69
62
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemymvc",
3
3
  "description": "MVC framework for Node.js",
4
- "version": "1.3.17",
4
+ "version": "1.3.18",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",