total5 0.0.1-9 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/api.js +18 -10
  2. package/bin/flow5 +142 -0
  3. package/bin/total5 +166 -905
  4. package/builders.js +90 -35
  5. package/changelog.txt +3 -1
  6. package/cluster.js +1 -1
  7. package/cms.js +185 -51
  8. package/controller.js +233 -70
  9. package/cron.js +1 -1
  10. package/debug.js +12 -5
  11. package/edit.js +26 -33
  12. package/filestorage.js +38 -17
  13. package/flow-flowstream.js +199 -68
  14. package/flow.js +16 -10
  15. package/flowstream.js +4 -3
  16. package/global.js +84 -1
  17. package/htmlparser.js +41 -29
  18. package/http.js +3 -1
  19. package/image.js +4 -0
  20. package/images.js +1 -1
  21. package/index.js +246 -117
  22. package/jsonschema.js +21 -17
  23. package/macros.js +222 -0
  24. package/mail.js +11 -27
  25. package/markdown.js +21 -11
  26. package/minificators.js +1 -1
  27. package/nosql-querybuilder.js +4 -0
  28. package/nosql.js +8 -0
  29. package/openclient.js +1 -1
  30. package/package.json +4 -3
  31. package/pause.html +1 -1
  32. package/release.js +1 -1
  33. package/routing.js +118 -35
  34. package/sourcemap.js +6 -3
  35. package/test.js +9 -2
  36. package/tms.js +11 -14
  37. package/uibuilder.js +59 -23
  38. package/utils.js +147 -102
  39. package/viewengine.js +19 -8
  40. package/websocket.js +10 -6
  41. package/503.html +0 -65
  42. package/CONTRIBUTING.md +0 -55
  43. package/helpers/index.js +0 -32
  44. package/templates.json +0 -74
  45. package/tests/bundles/index.js +0 -25
  46. package/tests/cron.js +0 -0
  47. package/tests/htmlparser.js +0 -0
  48. package/tests/minifactors.js +0 -17
  49. package/tests/nosql.js +0 -18
  50. package/tests/proxy/index.js +0 -21
  51. package/tests/routing/index.js +0 -27
  52. package/tests/schemas.js +0 -17
  53. package/tests/server/index.js +0 -24
  54. package/tests/staticfiles/index.js +0 -24
  55. package/tests/utils.js +0 -17
  56. package/tmsclient.js +0 -125
  57. package/todo.txt +0 -11
  58. package/tools/beta.sh +0 -6
  59. package/tools/release.sh +0 -6
package/controller.js CHANGED
@@ -11,17 +11,23 @@ const REG_MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Min
11
11
  const REG_ENCODINGCLEANER = /[;\s]charset=utf-8/g;
12
12
 
13
13
  const CHECK_DATA = { POST: 1, PUT: 1, PATCH: 1, DELETE: 1 };
14
- const CHECK_COMPRESSION = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'application/xml': true, 'text/xml': true, 'image/svg+xml': true, 'text/x-markdown': true, 'text/html': true };
15
- const CHECK_CHARSET = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'text/xml': true, 'text/x-markdown': true, 'text/html': true };
14
+ const CHECK_COMPRESSION = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'application/xml': true, 'text/xml': true, 'image/svg+xml': true, 'text/x-markdown': true, 'text/html': true, 'application/x-ipynb+json': true, 'application/x-ijsnb+json': true };
15
+ const CHECK_CHARSET = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'text/xml': true, 'text/x-markdown': true, 'text/html': true, 'application/x-ijsnb+json': true, 'application/x-ipynb+json': true };
16
16
  const CHECK_NOCACHE = { zip: 1, rar: 1 };
17
+ const CHECK_MIN = /(\.|-|@)min/i;
17
18
 
18
19
  const GZIP_FILE = { memLevel: 9 };
19
20
  const GZIP_STREAM = { memLevel: 1 };
20
21
 
22
+ const NOCACHE = 'private, no-cache, no-store, max-age=0';
23
+
21
24
  function Controller(req, res) {
22
25
 
23
26
  var ctrl = this;
24
27
 
28
+ req.controller = ctrl;
29
+
30
+ ctrl.timeout = F.config.$httptimeout;
25
31
  ctrl.req = req;
26
32
  ctrl.res = res;
27
33
  ctrl.method = ctrl.req.method;
@@ -58,7 +64,7 @@ function Controller(req, res) {
58
64
 
59
65
  ctrl.response = {
60
66
  status: 200,
61
- cache: DEBUG,
67
+ cache: global.DEBUG != true,
62
68
  minify: true,
63
69
  // minifyjson: false
64
70
  // encrypt: false
@@ -206,14 +212,28 @@ Controller.prototype.html = function(value) {
206
212
 
207
213
  ctrl.response.headers['content-type'] = 'text/html';
208
214
 
209
- if (value != null) {
215
+ if (value != null)
210
216
  ctrl.response.value = ctrl.response.minify && F.config.$minifyhtml ? F.TMinificators.html(value) : value;
211
- }
212
217
 
213
218
  ctrl.flush();
214
219
  F.stats.response.html++;
215
220
  };
216
221
 
222
+ Controller.prototype.xml = function(value) {
223
+ var ctrl = this;
224
+
225
+ if (ctrl.destroyed)
226
+ return;
227
+
228
+ if (value != null)
229
+ ctrl.response.value = value;
230
+
231
+ ctrl.response.headers['content-type'] = 'text/xml';
232
+ ctrl.flush();
233
+
234
+ F.stats.response.xml++;
235
+ };
236
+
217
237
  Controller.prototype.text = Controller.prototype.plain = function(value) {
218
238
  var ctrl = this;
219
239
 
@@ -229,6 +249,28 @@ Controller.prototype.text = Controller.prototype.plain = function(value) {
229
249
  F.stats.response.text++;
230
250
  };
231
251
 
252
+ Controller.prototype.respond = function(value, a, b) {
253
+ var ctrl = this;
254
+ var output = ctrl.response.output;
255
+ switch (output) {
256
+ case 'html':
257
+ case 'plain':
258
+ case 'text':
259
+ case 'xml':
260
+ case 'json':
261
+ case 'redirect':
262
+ case 'jsonstring':
263
+ case 'empty':
264
+ case 'file':
265
+ ctrl[output](value, a, b);
266
+ break;
267
+ default:
268
+ ctrl.json(value, a, b);
269
+ break;
270
+ }
271
+ return ctrl;
272
+ };
273
+
232
274
  Controller.prototype.json = function(value, beautify, replacer) {
233
275
  var ctrl = this;
234
276
 
@@ -237,7 +279,7 @@ Controller.prototype.json = function(value, beautify, replacer) {
237
279
 
238
280
  var response = ctrl.response;
239
281
  response.headers['content-type'] = 'application/json';
240
- response.headers['cache-control'] = 'private, no-cache, no-store, max-age=0';
282
+ response.headers['cache-control'] = NOCACHE;
241
283
  response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
242
284
  response.headers.expires = '-1';
243
285
  response.value = JSON.stringify(value, beautify ? '\t' : null, replacer);
@@ -253,7 +295,7 @@ Controller.prototype.jsonstring = function(value) {
253
295
 
254
296
  var response = ctrl.response;
255
297
  response.headers['content-type'] = 'application/json';
256
- response.headers['cache-control'] = 'private, no-cache, no-store, max-age=0';
298
+ response.headers['cache-control'] = NOCACHE;
257
299
  response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
258
300
  response.headers.expires = '-1';
259
301
  response.value = value;
@@ -291,7 +333,7 @@ Controller.prototype.invalid = function(value) {
291
333
  }
292
334
 
293
335
  response.headers['content-type'] = 'application/json';
294
- response.headers['cache-control'] = 'private, no-cache, no-store, max-age=0';
336
+ response.headers['cache-control'] = NOCACHE;
295
337
  response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
296
338
  response.value = JSON.stringify(err.output(ctrl.language));
297
339
  response.status = err.status === 408 ? 503 : err.status;
@@ -332,8 +374,8 @@ Controller.prototype.flush = function() {
332
374
  response.headers['content-encoding'] = 'gzip';
333
375
  ctrl.res.writeHead(response.status, response.headers);
334
376
  ctrl.res.end(buffer, 'utf8');
335
- ctrl.free();
336
377
  F.stats.performance.upload += buffer.length / 1024 / 1024;
378
+ ctrl.free();
337
379
  }
338
380
  });
339
381
  return;
@@ -343,9 +385,12 @@ Controller.prototype.flush = function() {
343
385
  if (CHECK_CHARSET[type])
344
386
  response.headers['content-type'] += '; charset=utf-8';
345
387
 
346
- ctrl.res.writeHead(response.status, response.headers);
347
- ctrl.res.end(buffer);
348
- ctrl.free();
388
+ try {
389
+ ctrl.res.writeHead(response.status, response.headers);
390
+ ctrl.res.end(buffer);
391
+ } finally {
392
+ ctrl.free();
393
+ }
349
394
  };
350
395
 
351
396
  Controller.prototype.fallback = function(code, err) {
@@ -376,7 +421,7 @@ Controller.prototype.fallback = function(code, err) {
376
421
  ctrl.response.status = 503;
377
422
  if (!view) {
378
423
  F.temporary.views.$pause = view = new F.TViewEngine.View();
379
- view.compiled = F.TViewEngine.compile('$pause', F.Fs.readFileSync(F.Path.join(F.config.$nodemodules, 'total5/pause.html'), 'utf8'), false);
424
+ view.compiled = F.TViewEngine.compile('$pause', F.Fs.readFileSync(F.Path.join(F.config.$total5, 'pause.html'), 'utf8'), false);
380
425
  }
381
426
  view.model = F.paused;
382
427
  } else {
@@ -384,7 +429,7 @@ Controller.prototype.fallback = function(code, err) {
384
429
  view = F.temporary.views.$error;
385
430
  if (!view) {
386
431
  F.temporary.views.$error = view = new F.TViewEngine.View();
387
- view.compiled = F.TViewEngine.compile('$error', F.Fs.readFileSync(F.Path.join(F.config.$nodemodules, 'total5/error.html'), 'utf8'), false);
432
+ view.compiled = F.TViewEngine.compile('$error', F.Fs.readFileSync(F.Path.join(F.config.$total5, 'error.html'), 'utf8'), false);
388
433
  }
389
434
  view.model = { code: code, status: F.TUtils.httpstatus(code), error: err ? (DEBUG ? err.toString() : '') : '' };
390
435
  }
@@ -393,6 +438,11 @@ Controller.prototype.fallback = function(code, err) {
393
438
  }
394
439
  };
395
440
 
441
+ Controller.prototype.layout = function(name) {
442
+ var ctrl = this;
443
+ ctrl.response.layout = name;
444
+ };
445
+
396
446
  Controller.prototype.view = function(name, model) {
397
447
 
398
448
  var ctrl = this;
@@ -401,10 +451,15 @@ Controller.prototype.view = function(name, model) {
401
451
  return;
402
452
 
403
453
  var view = new F.TViewEngine.View(ctrl);
404
- var output = view.render(name, model);
405
- ctrl.html(output);
454
+ ctrl.response.layout && view.layout(ctrl.response.layout);
455
+ setImmediate(renderview, view, name, model);
456
+ return view;
406
457
  };
407
458
 
459
+ function renderview(view, name, model) {
460
+ view.controller.html(view.render(name, model));
461
+ }
462
+
408
463
  Controller.prototype.file = function(path, download) {
409
464
 
410
465
  var ctrl = this;
@@ -423,14 +478,23 @@ Controller.prototype.file = function(path, download) {
423
478
  var ext = F.TUtils.getExtension(path);
424
479
 
425
480
  if (ext === 'js') {
426
- if (response.minify)
481
+ if (response.minify) {
427
482
  response.minify = F.config.$minifyjs;
483
+ if (response.minify)
484
+ response.minify = !CHECK_MIN.test(path);
485
+ }
428
486
  } else if (ext === 'css') {
429
- if (response.minify)
487
+ if (response.minify) {
430
488
  response.minify = F.config.$minifycss;
489
+ if (response.minify)
490
+ response.minify = !CHECK_MIN.test(path);
491
+ }
431
492
  } else if (ext === 'html') {
432
- if (response.minify)
493
+ if (response.minify) {
433
494
  response.minify = F.config.$minifyhtml;
495
+ if (response.minify)
496
+ response.minify = !CHECK_MIN.test(path);
497
+ }
434
498
  }
435
499
 
436
500
  if (response.minify) {
@@ -477,7 +541,7 @@ Controller.prototype.stream = function(type, stream, download) {
477
541
  if (CHECK_CHARSET[type])
478
542
  type += '; charset=utf-8';
479
543
 
480
- response.headers['content-type'] = type;
544
+ response.headers['content-type'] = type || 'application/octet-stream';
481
545
 
482
546
  if (compress)
483
547
  response.headers['content-encoding'] = 'gzip';
@@ -595,6 +659,30 @@ Controller.prototype.proxy = function(opt) {
595
659
 
596
660
  };
597
661
 
662
+ Controller.prototype.successful = function(callback) {
663
+ var ctrl = this;
664
+ return function(err, a, b, c) {
665
+ if (err)
666
+ ctrl.invalid(err);
667
+ else
668
+ callback.call(ctrl, a, b, c);
669
+ };
670
+ };
671
+
672
+ Controller.prototype.done = function(arg) {
673
+ var ctrl = this;
674
+ return function(err, response) {
675
+ if (err)
676
+ ctrl.invalid(err);
677
+ else
678
+ ctrl.json(DEF.onSuccess(arg === true ? response : arg));
679
+ };
680
+ };
681
+
682
+ Controller.prototype.transform = function(name, value, callback) {
683
+ return F.transform(name, value, callback, this);
684
+ };
685
+
598
686
  Controller.prototype.success = function(value) {
599
687
  F.TUtils.success.value = value;
600
688
  this.json(F.TUtils.success);
@@ -735,13 +823,22 @@ Controller.prototype.resume = function() {
735
823
 
736
824
  switch (ctrl.ext) {
737
825
  case 'js':
738
- send_js(ctrl, path);
826
+ if (CHECK_MIN.test(path))
827
+ send_file(ctrl, path, ctrl.ext);
828
+ else
829
+ send_js(ctrl, path);
739
830
  break;
740
831
  case 'css':
741
- send_css(ctrl, path);
832
+ if (CHECK_MIN.test(path))
833
+ send_file(ctrl, path, ctrl.ext);
834
+ else
835
+ send_css(ctrl, path);
742
836
  break;
743
837
  case 'html':
744
- send_html(ctrl, path);
838
+ if (CHECK_MIN.test(path))
839
+ send_file(ctrl, path, ctrl.ext);
840
+ else
841
+ send_html(ctrl, path);
745
842
  break;
746
843
  default:
747
844
  send_file(ctrl, path, ctrl.ext);
@@ -764,14 +861,15 @@ Controller.prototype.free = function() {
764
861
  ctrl.payload = null;
765
862
 
766
863
  // Potential problem
767
- ctrl.body = null;
768
- ctrl.params = null;
769
- ctrl.query = null;
864
+ // ctrl.body = null;
865
+ // ctrl.params = null;
866
+ // ctrl.query = null;
770
867
 
771
868
  if (ctrl.preventclearfiles != true)
772
869
  ctrl.clear();
773
870
 
774
871
  // Clear resources
872
+ ctrl.req.controller = null;
775
873
 
776
874
  };
777
875
 
@@ -824,7 +922,7 @@ Controller.prototype.$route = function() {
824
922
 
825
923
  ctrl.req.on('data', function(chunk) {
826
924
  ctrl.payloadsize += chunk.length;
827
- if ((ctrl.payloadsize / 1024) > ctrl.route.size) {
925
+ if (ctrl.payloadsize > ctrl.route.size) {
828
926
  if (!ctrl.toolarge) {
829
927
  ctrl.toolarge = true;
830
928
  delete ctrl.payload;
@@ -889,16 +987,33 @@ function readfile(filename, callback) {
889
987
  });
890
988
  }
891
989
 
892
- function notmodified(ctrl, date) {
990
+ Controller.prototype.notmodified = function(date) {
991
+ var ctrl = this;
893
992
  if (ctrl.headers['if-modified-since'] === date) {
894
993
  ctrl.response.status = 304;
895
- ctrl.response.headers['cache-control'] = 'public, max-age=11111111';
994
+ ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 min.
896
995
  ctrl.response.headers['last-modified'] = date;
897
996
  ctrl.flush();
898
997
  F.stats.response.notmodified++;
899
998
  return true;
900
999
  }
901
- }
1000
+ };
1001
+
1002
+ Controller.prototype.httpcache = function(date) {
1003
+ var ctrl = this;
1004
+
1005
+ if (date instanceof Date)
1006
+ date = date.toUTCString();
1007
+
1008
+ if (!ctrl.response.headers.expires)
1009
+ ctrl.response.headers.expires = F.config.$httpexpire;
1010
+
1011
+ if (!ctrl.response.headers['cache-control'])
1012
+ ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 minute cache for revalidate (304)
1013
+
1014
+ ctrl.response.headers['last-modified'] = date;
1015
+ ctrl.response.headers.etag = '858' + F.config.$httpetag;
1016
+ };
902
1017
 
903
1018
  function multipart(ctrl) {
904
1019
 
@@ -938,6 +1053,7 @@ function multipart(ctrl) {
938
1053
  if (index !== -1)
939
1054
  file.filename = file.filename.substring(index + 1);
940
1055
 
1056
+ file.ext = F.TUtils.getExtension(file.filename);
941
1057
  ctrl.files.push(file);
942
1058
  }
943
1059
 
@@ -961,7 +1077,7 @@ function multipart(ctrl) {
961
1077
  });
962
1078
 
963
1079
  parser.skipcheck = !F.config.$httpchecktypes;
964
- parser.limits.total = ctrl.route.size * 1024; // to bytes
1080
+ parser.limits.total = ctrl.route.size;
965
1081
  }
966
1082
 
967
1083
  function authorize(ctrl) {
@@ -988,21 +1104,25 @@ function authorize(ctrl) {
988
1104
  execute(ctrl);
989
1105
  }
990
1106
 
991
- function execute(ctrl) {
1107
+ function execute(ctrl, skipmiddleware) {
992
1108
 
993
- ctrl.timeout = ctrl.route.timeout || F.config.$httptimeout;
1109
+ if (ctrl.route.timeout)
1110
+ ctrl.timeout = ctrl.route.timeout;
994
1111
 
995
1112
  for (let param of ctrl.route.params) {
996
1113
  let value = ctrl.split[param.index];
997
1114
  ctrl.params[param.name] = value;
998
1115
  }
999
1116
 
1000
- if (!ctrl.language && F.def.onLocalize)
1117
+ if (!ctrl.language && F.def.onLocalize) {
1001
1118
  ctrl.language = F.def.onLocalize(ctrl);
1119
+ ctrl.uri.cache += ctrl.language;
1120
+ }
1002
1121
 
1003
- if (ctrl.route.middleware.length) {
1122
+ if (!skipmiddleware && ctrl.route.middleware.length) {
1004
1123
  middleware(ctrl);
1005
1124
  } else {
1125
+
1006
1126
  if (ctrl.route.api) {
1007
1127
  let body = ctrl.body;
1008
1128
  if (body && typeof(body) === 'object' && body.schema && typeof(body.schema) === 'string') {
@@ -1026,17 +1146,40 @@ function execute(ctrl) {
1026
1146
 
1027
1147
  let params = {};
1028
1148
  if (endpoint.params) {
1029
- for (let m of endpoint.params)
1149
+ let err = null;
1150
+ for (let m of endpoint.params) {
1030
1151
  params[m.name] = schema[m.index] || '';
1152
+ if (!params[m.name]) {
1153
+ if (!err)
1154
+ err = new F.TBuilders.ErrorBuilder();
1155
+ err.push2('params.' + m.name);
1156
+ }
1157
+ }
1158
+ if (err) {
1159
+ ctrl.invalid(err);
1160
+ return;
1161
+ }
1031
1162
  }
1163
+
1032
1164
  body = body.data;
1165
+
1033
1166
  if (!body || typeof(body) === 'object') {
1167
+
1168
+ if (endpoint.timeout)
1169
+ ctrl.timeout = endpoint.timeout;
1170
+
1034
1171
  ctrl.params = params;
1035
1172
  ctrl.query = query ? query.parseEncoded() : {};
1036
- F.action(endpoint.actions, body || {}, ctrl).autorespond();
1173
+ let action = endpoint.action;
1174
+ if (action) {
1175
+ ctrl.body = body || {};
1176
+ action(ctrl);
1177
+ } else
1178
+ F.action(endpoint.actions, body || {}, ctrl).autorespond();
1037
1179
  return;
1038
1180
  }
1039
1181
  }
1182
+
1040
1183
  ctrl.fallback(400, 'Invalid data');
1041
1184
  }
1042
1185
  } else {
@@ -1062,12 +1205,17 @@ function auto_view(ctrl) {
1062
1205
 
1063
1206
  function send_html(ctrl, path) {
1064
1207
 
1065
- if (F.temporary.notfound[ctrl.uri.key]) {
1208
+ if (!ctrl.language && F.def.onLocalize) {
1209
+ ctrl.language = F.def.onLocalize(ctrl);
1210
+ ctrl.uri.cache += ctrl.language;
1211
+ }
1212
+
1213
+ if (F.temporary.notfound[ctrl.uri.cache]) {
1066
1214
  ctrl.fallback(404);
1067
1215
  return;
1068
1216
  }
1069
1217
 
1070
- let filename = F.temporary.minified[ctrl.uri.key];
1218
+ let filename = F.temporary.minified[ctrl.uri.cache];
1071
1219
  if (filename) {
1072
1220
  send_file(ctrl, filename, 'html');
1073
1221
  return;
@@ -1076,32 +1224,33 @@ function send_html(ctrl, path) {
1076
1224
  readfile(path, function(err, output) {
1077
1225
 
1078
1226
  if (err) {
1079
- F.temporary.notfound[ctrl.uri.key] = 1;
1227
+
1228
+ if (!DEBUG)
1229
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1230
+
1080
1231
  ctrl.fallback(404);
1081
1232
  return;
1082
1233
  }
1083
1234
 
1084
- if (!ctrl.language && F.def.onLocalize)
1085
- ctrl.language = F.def.onLocalize(ctrl);
1086
-
1087
1235
  output.body = F.translate(ctrl.language, output.body);
1088
1236
 
1089
1237
  if (ctrl.response.minify && F.config.$minifyhtml)
1090
1238
  output.body = F.TMinificators.html(output.body);
1091
1239
 
1092
1240
  if (DEBUG) {
1241
+ ctrl.response.headers['cache-control'] = NOCACHE;
1093
1242
  ctrl.response.headers['last-modified'] = output.date;
1094
1243
  ctrl.response.headers['content-type'] = 'text/html';
1095
1244
  ctrl.response.value = output.body;
1096
1245
  ctrl.flush();
1097
1246
  } else {
1098
- let filename = F.path.tmp(F.clusterid + (ctrl.language ? (ctrl.language + '-') : '') + ctrl.uri.key.substring(1).replace(REG_FILETMP, '-') + '-min.html');
1247
+ let filename = F.path.tmp(F.clusterid + ctrl.uri.cache.substring(1).replace(REG_FILETMP, '-') + '-min.html');
1099
1248
  F.Fs.writeFile(filename, output.body, function(err) {
1100
1249
  if (err) {
1101
- F.temporary.notfound[ctrl.uri.key] = 1;
1250
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1102
1251
  ctrl.fallback(404, err.toString());
1103
1252
  } else {
1104
- F.temporary.minified[ctrl.uri.key] = filename;
1253
+ F.temporary.minified[ctrl.uri.cache] = filename;
1105
1254
  send_file(ctrl, filename, 'html');
1106
1255
  }
1107
1256
  });
@@ -1111,12 +1260,12 @@ function send_html(ctrl, path) {
1111
1260
 
1112
1261
  function send_css(ctrl, path) {
1113
1262
 
1114
- if (F.temporary.notfound[ctrl.uri.key]) {
1263
+ if (F.temporary.notfound[ctrl.uri.cache]) {
1115
1264
  ctrl.fallback(404);
1116
1265
  return;
1117
1266
  }
1118
1267
 
1119
- let filename = F.temporary.minified[ctrl.uri.key];
1268
+ let filename = F.temporary.minified[ctrl.uri.cache];
1120
1269
  if (filename) {
1121
1270
  send_file(ctrl, filename, 'css');
1122
1271
  return;
@@ -1125,7 +1274,10 @@ function send_css(ctrl, path) {
1125
1274
  readfile(path, function(err, output) {
1126
1275
 
1127
1276
  if (err) {
1128
- F.temporary.notfound[ctrl.uri.key] = 1;
1277
+
1278
+ if (!DEBUG)
1279
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1280
+
1129
1281
  ctrl.fallback(404);
1130
1282
  return;
1131
1283
  }
@@ -1134,18 +1286,19 @@ function send_css(ctrl, path) {
1134
1286
  output.body = F.TMinificators.css(output.body);
1135
1287
 
1136
1288
  if (DEBUG) {
1289
+ ctrl.response.headers['cache-control'] = NOCACHE;
1137
1290
  ctrl.response.headers['last-modified'] = output.date;
1138
1291
  ctrl.response.headers['content-type'] = 'text/css';
1139
1292
  ctrl.response.value = output.body;
1140
1293
  ctrl.flush();
1141
1294
  } else {
1142
- let filename = F.path.tmp(F.clusterid + ctrl.uri.key.substring(1).replace(REG_FILETMP, '-') + '-min.css');
1295
+ let filename = F.path.tmp(F.clusterid + ctrl.uri.cache.substring(1).replace(REG_FILETMP, '-') + '-min.css');
1143
1296
  F.Fs.writeFile(filename, output.body, function(err) {
1144
1297
  if (err) {
1145
- F.temporary.notfound[ctrl.uri.key] = 1;
1298
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1146
1299
  ctrl.fallback(404, err.toString());
1147
1300
  } else {
1148
- F.temporary.minified[ctrl.uri.key] = filename;
1301
+ F.temporary.minified[ctrl.uri.cache] = filename;
1149
1302
  send_file(ctrl, filename, 'css');
1150
1303
  }
1151
1304
  });
@@ -1155,12 +1308,12 @@ function send_css(ctrl, path) {
1155
1308
 
1156
1309
  function send_js(ctrl, path) {
1157
1310
 
1158
- if (F.temporary.notfound[ctrl.uri.key]) {
1311
+ if (F.temporary.notfound[ctrl.uri.cache]) {
1159
1312
  ctrl.fallback(404);
1160
1313
  return;
1161
1314
  }
1162
1315
 
1163
- let filename = F.temporary.minified[ctrl.uri.key];
1316
+ let filename = F.temporary.minified[ctrl.uri.cache];
1164
1317
  if (filename) {
1165
1318
  send_file(ctrl, filename, 'js');
1166
1319
  return;
@@ -1169,7 +1322,10 @@ function send_js(ctrl, path) {
1169
1322
  readfile(path, function(err, output) {
1170
1323
 
1171
1324
  if (err) {
1172
- F.temporary.notfound[ctrl.uri.key] = 1;
1325
+
1326
+ if (!DEBUG)
1327
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1328
+
1173
1329
  ctrl.fallback(404);
1174
1330
  return;
1175
1331
  }
@@ -1178,18 +1334,19 @@ function send_js(ctrl, path) {
1178
1334
  output.body = F.TMinificators.js(output.body);
1179
1335
 
1180
1336
  if (DEBUG) {
1337
+ ctrl.response.headers['cache-control'] = NOCACHE;
1181
1338
  ctrl.response.headers['last-modified'] = output.date;
1182
1339
  ctrl.response.headers['content-type'] = 'text/javascript';
1183
1340
  ctrl.response.value = output.body;
1184
1341
  ctrl.flush();
1185
1342
  } else {
1186
- let filename = F.path.tmp(F.clusterid + ctrl.uri.key.substring(1).replace(REG_FILETMP, '-') + '-min.js');
1343
+ let filename = F.path.tmp(F.clusterid + ctrl.uri.cache.substring(1).replace(REG_FILETMP, '-') + '-min.js');
1187
1344
  F.Fs.writeFile(filename, output.body, function(err) {
1188
1345
  if (err) {
1189
- F.temporary.notfound[ctrl.uri.key] = 1;
1346
+ F.temporary.notfound[ctrl.uri.cache] = 1;
1190
1347
  ctrl.fallback(404, err.toString());
1191
1348
  } else {
1192
- F.temporary.minified[ctrl.uri.key] = filename;
1349
+ F.temporary.minified[ctrl.uri.cache] = filename;
1193
1350
  send_file(ctrl, filename, 'js');
1194
1351
  }
1195
1352
  });
@@ -1200,15 +1357,15 @@ function send_js(ctrl, path) {
1200
1357
  function send_file(ctrl, path, ext) {
1201
1358
 
1202
1359
  // Check the file existence
1203
- if (F.temporary.notfound[ctrl.uri.key]) {
1360
+ if (F.temporary.notfound[ctrl.uri.cache]) {
1204
1361
  ctrl.fallback(404);
1205
1362
  return;
1206
1363
  }
1207
1364
 
1208
- var cache = F.temporary.tmp[ctrl.uri.key];
1365
+ var cache = F.temporary.tmp[ctrl.uri.cache];
1209
1366
 
1210
1367
  // HTTP Cache
1211
- if (ctrl.response.cache && cache && notmodified(ctrl, cache.date))
1368
+ if (ctrl.response.cache && cache && ctrl.notmodified(cache.date))
1212
1369
  return;
1213
1370
 
1214
1371
  var accept = ctrl.headers['accept-encoding'];
@@ -1221,18 +1378,24 @@ function send_file(ctrl, path, ext) {
1221
1378
 
1222
1379
  if (err) {
1223
1380
 
1224
- if (ctrl.response.cache)
1225
- F.temporary.notfound[ctrl.uri.key] = true;
1381
+ if (!DEBUG && ctrl.response.cache)
1382
+ F.temporary.notfound[ctrl.uri.cache] = true;
1226
1383
 
1227
1384
  ctrl.fallback(404);
1228
1385
  return;
1229
1386
  }
1230
1387
 
1231
- if (httpcache)
1232
- ctrl.response.headers.expires = F.config.$httpexpire;
1233
- else if (ctrl.response.headers.expires)
1388
+ if (httpcache) {
1389
+ if (!ctrl.response.headers.expires)
1390
+ ctrl.response.headers.expires = F.config.$httpexpire;
1391
+ if (!ctrl.response.headers['cache-control'])
1392
+ ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 minute cache for revalidate (304)
1393
+ } else if (ctrl.response.headers.expires)
1234
1394
  delete ctrl.response.headers.expires;
1235
1395
 
1396
+ if (!httpcache)
1397
+ ctrl.response.headers['cache-control'] = NOCACHE;
1398
+
1236
1399
  if (!cache)
1237
1400
  cache = { date: stats.mtime.toUTCString(), size: stats.size };
1238
1401
 
@@ -1245,7 +1408,7 @@ function send_file(ctrl, path, ext) {
1245
1408
  type += '; charset=utf-8';
1246
1409
 
1247
1410
  ctrl.response.headers['content-type'] = type;
1248
- F.temporary.tmp[ctrl.uri.key] = cache;
1411
+ F.temporary.tmp[ctrl.uri.cache] = cache;
1249
1412
 
1250
1413
  F.stats.performance.open++;
1251
1414
 
@@ -1303,7 +1466,7 @@ function send_file(ctrl, path, ext) {
1303
1466
 
1304
1467
  function middleware(ctrl) {
1305
1468
  var run = function(index) {
1306
- var name = ctrl.route.middleware[index];
1469
+ let name = ctrl.route.middleware[index];
1307
1470
  if (name) {
1308
1471
  let fn = F.routes.middleware[name];
1309
1472
  if (fn)
@@ -1311,7 +1474,7 @@ function middleware(ctrl) {
1311
1474
  else
1312
1475
  run(index + 1);
1313
1476
  } else
1314
- ctrl.route.action(ctrl);
1477
+ execute(ctrl, true);
1315
1478
  };
1316
1479
  run(0);
1317
1480
  }
@@ -1372,7 +1535,7 @@ HttpFile.prototype.$move = function(filename, callback) {
1372
1535
  } else {
1373
1536
  if (!err) {
1374
1537
  self.path = filename;
1375
- self.rem = false;
1538
+ self.removable = false;
1376
1539
  }
1377
1540
  callback && callback(err);
1378
1541
  }
package/cron.js CHANGED
@@ -28,7 +28,7 @@ function cronexec(output, date) {
28
28
  break;
29
29
  }
30
30
  } else if (m.type === 'every') {
31
- if (m.value % val !== 0) {
31
+ if (m.value[i] !== '*' && m.value[i] % val !== 0) {
32
32
  is = false;
33
33
  break;
34
34
  }