expediate 0.0.2 → 0.0.3

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 (4) hide show
  1. package/README.md +2 -1
  2. package/index.js +57 -18
  3. package/package.json +1 -1
  4. package/static.js +40 -12
package/README.md CHANGED
@@ -6,10 +6,11 @@ however it doesn't intent to provide all the features.
6
6
 
7
7
  [![NPM Version][npm-image]][npm-url]
8
8
  [![NPM Downloads][downloads-image]][downloads-url]
9
+ <!--
9
10
  [![Linux Build][travis-image]][travis-url]
10
11
  [![Windows Build][appveyor-image]][appveyor-url]
11
12
  [![Test Coverage][coveralls-image]][coveralls-url]
12
-
13
+ -->
13
14
  ```js
14
15
  const expediate = require('expediate')
15
16
  const app = expediate()
package/index.js CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  const http = require('http'),
24
24
  https = require('https'),
25
- serveStatic = require('./static.js');
25
+ serv = require('./static.js');
26
26
 
27
27
  /**
28
28
  * Prepare an layer object to define a new route
@@ -35,11 +35,15 @@ const http = require('http'),
35
35
  function buildRouteLayer(method, path, listener) {
36
36
  if (method)
37
37
  method = method.toUpperCase();
38
- if (typeof path === 'function') {
38
+ if (typeof path !== 'string' && !(path instanceof RegExp)) {
39
39
  listener = path;
40
40
  path = '/';
41
41
  }
42
- let parts = path.split('/').filter(x => x.length > 0);
42
+ let parts = path instanceof RegExp ? null : path.split('/').filter(x => x.length > 0);
43
+ if (listener && typeof listener !== 'function')
44
+ listener = listener.listener // Route object
45
+ if (typeof listener !== 'function')
46
+ throw new TypeError('Incorrect listener type');
43
47
  return { method, path, parts, listener };
44
48
  };
45
49
 
@@ -54,14 +58,28 @@ function buildRouteLayer(method, path, listener) {
54
58
  * @param {String[]} parts
55
59
  * @return {Bool}
56
60
  */
57
- function matchRouteLayer(layer, req, parts) {
61
+ function matchRouteLayer(layer, req, parts, path) {
58
62
  if (layer.method && layer.method != req.method)
59
63
  return false;
60
64
  let params = {}
61
65
  for (let i = 0; ; ++i) {
66
+ if (layer.parts == null) {
67
+ var m = layer.path.exec(path);
68
+ if (m == null)
69
+ return false;
70
+ for (let i = 1; i < m.length; ++i)
71
+ params[i] = m[i];
72
+ req.path = m.index == 0 ? path.replace(m[0], '') : path;
73
+ req.queries.route = params;
74
+ for (var k in params)
75
+ req.params[k] = params[k];
76
+ return true;
77
+ }
62
78
  if (layer.parts.length <= i) {
63
79
  req.path = '/' + parts.slice(i).join('/');
64
80
  req.queries.route = params;
81
+ for (var k in params)
82
+ req.params[k] = params[k];
65
83
  return true;
66
84
  } else if (parts.length <= i)
67
85
  return false;
@@ -93,21 +111,19 @@ function updateHttpObject(req, res) {
93
111
  for(var pair of qry.searchParams.entries())
94
112
  params[pair[0]] = pair[1];
95
113
  req.queries.url = params;
114
+ req.params = params;
96
115
 
97
116
  // Parse cookies
98
117
  if (req.cookies == null) {
99
118
  req.cookies = {};
100
- var cookies = req.headers.cookie;
101
- if (cookies) {
102
- cookies = cookies.split(';')
119
+ if (req.headers.cookie) {
120
+ const dico = req.headers.cookie.split(';')
103
121
  .map(x => x.replace(/^\s+|\s+$/g, '').split('='));
104
- for (var k in cookies) {
105
- let key = cookies[k][0]
106
- let val = cookies[k][1]
122
+ for (var k in dico) {
123
+ let key = dico[k][0]
124
+ let val = dico[k][1]
107
125
  req.cookies[key] = val;
108
- if (typeof val == 'string') {
109
- // TODO s: Cookie is signed, j: Cookie is a JSON
110
- }
126
+ // TODO s: Cookie is signed, j: Cookie is a JSON
111
127
  }
112
128
  }
113
129
  }
@@ -116,15 +132,16 @@ function updateHttpObject(req, res) {
116
132
  res.setHeader('X-Powered-By', 'Expediate');
117
133
 
118
134
  res.send = (data) => {
119
- res.write(data);
135
+ if (data)
136
+ res.write(data);
120
137
  res.end();
121
138
  }
122
139
 
123
140
  res.status = (code, headers) => {
141
+ res.statusCode = code;
124
142
  if (headers)
125
143
  for (var k in headers)
126
144
  res.setHeader(k, headers[k])
127
- res.writeHead(code)
128
145
  return res;
129
146
  };
130
147
 
@@ -187,7 +204,7 @@ function Router() {
187
204
  const next = () => {
188
205
  while (idx < routes.length) {
189
206
  let layer = routes[idx++];
190
- if (matchRouteLayer(layer, req, parts))
207
+ if (matchRouteLayer(layer, req, parts, req.path))
191
208
  return layer.listener(req, res, next);
192
209
  }
193
210
 
@@ -247,13 +264,35 @@ Router.logger = () => {
247
264
  const user = req.session ? `${req.session.username}/${req.session.ssid}` : '-'
248
265
  const status = `${clr}${res.statusCode}${nclr}`
249
266
  const elp = `${req.elapsed} ms`
250
- console.log(`${rec} ${status} ${req.method} ${path} ${ip} <${user}> ${elp}`);
267
+ const len = res.getHeader('content-length') ? res.getHeader('content-length') : '-';
268
+ console.log(`${rec} ${status} ${req.method} ${path} ${ip} <${user}> ${elp} (${len})`);
251
269
  })
252
270
  next();
253
271
  };
254
272
  };
255
273
 
256
- Router.static = serveStatic;
274
+ Router.parseBody = () => {
275
+ return (req, res, next) => {
276
+ let data = '';
277
+ req.on('data', chunk => {
278
+ data += chunk;
279
+ });
280
+ req.on('end', () => {
281
+ try {
282
+ req.body = JSON.parse(data);
283
+ } catch {
284
+ req.body = data;
285
+ }
286
+ next();
287
+ });
288
+ }
289
+ }
290
+
291
+ Router.static = serv.serveStatic;
292
+ Router.file = serv.serveFile;
293
+ Router.sendFile = serv.sendFile;
294
+ Router.sendIndex = serv.sendIndex;
295
+
257
296
 
258
297
  Router.session = (opts) => {
259
298
  return (req, res, next) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expediate",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Fast and simple, minimalist web framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/static.js CHANGED
@@ -253,14 +253,14 @@ function sendFile(req, res, pathname, stat, opts) {
253
253
 
254
254
  // Conditionnal GET
255
255
  if (hasCondition(req.headers)) {
256
- if (!conditionMatch(req.headers, res.getHeaders())) {
257
- return HTTP.PRECONDITION_FAILS(res)
258
- }
256
+ if (conditionMatch(req.headers, res.getHeaders())) {
259
257
 
260
- if (isCacheFresh(req.headers, res.getHeaders())) {
261
- removeContentHeaders(res);
262
- return HTTP.NOT_MODIFIED(res);
258
+ if (isCacheFresh(req.headers, res.getHeaders())) {
259
+ removeContentHeaders(res);
260
+ return HTTP.NOT_MODIFIED(res);
261
+ }
263
262
  }
263
+ // return HTTP.PRECONDITION_FAILS(res)
264
264
  }
265
265
 
266
266
 
@@ -277,7 +277,7 @@ function sendFile(req, res, pathname, stat, opts) {
277
277
  });
278
278
  stream.on('error', err => {
279
279
  if (finished) return;
280
- console.log('ERROR', pathname, err)
280
+ console.warn('static error', pathname, err)
281
281
  HTTP.INTERNAL_ERROR(res, err.code);
282
282
  finished = true;
283
283
  destroyReadStream(stream);
@@ -310,7 +310,7 @@ function sendIndex(req, res, pathname, stat, opts) {
310
310
  })
311
311
  }
312
312
 
313
- function serveStatic (root, options) {
313
+ function serveOptions(root, options) {
314
314
 
315
315
  if (!root)
316
316
  throw new TypeError('root path required')
@@ -319,7 +319,7 @@ function serveStatic (root, options) {
319
319
 
320
320
  // copy options
321
321
  var opts = options || {
322
- fallthrough: false,
322
+ fallthrough: true,
323
323
  redirect: false,
324
324
  };
325
325
  opts.fallthrough = opts.fallthrough !== false
@@ -329,8 +329,13 @@ function serveStatic (root, options) {
329
329
  if (opts.setHeaders && typeof opts.setHeaders !== 'function')
330
330
  throw new TypeError('option setHeaders must be function')
331
331
 
332
+ return opts;
333
+ }
334
+
335
+ function serveStatic (root, options) {
332
336
 
333
- return function serveStatic (req, res, next) {
337
+ var opts = serveOptions(root, options);
338
+ return function (req, res, next) {
334
339
 
335
340
  if (req.method !== 'GET' && req.method !== 'HEAD') {
336
341
  if (opts.fallthrough)
@@ -338,7 +343,7 @@ function serveStatic (root, options) {
338
343
  return HTTP.NOT_ALLOWED(res);
339
344
  }
340
345
 
341
- var originalUrl = decodeURIComponent(req.originalUrl || req.path || req.url)
346
+ var originalUrl = decodeURIComponent(/*req.originalUrl || */req.path || req.url)
342
347
  var pathname = originalUrl
343
348
 
344
349
  // make sure redirect occurs at mount
@@ -365,6 +370,7 @@ function serveStatic (root, options) {
365
370
  if (err.code == 'ENOENT' || err.code == 'ENAMETOOLONG' || err.code == 'ENOTDIR') {
366
371
  if (opts.fallthrough)
367
372
  return next();
373
+ console.warn('static error:', err)
368
374
  return HTTP.NOT_FOUND(res)
369
375
  }
370
376
  return HTTP.INTERNAL_ERROR(res, err.code);
@@ -383,6 +389,28 @@ function serveStatic (root, options) {
383
389
  }
384
390
  }
385
391
 
392
+ function serveFile (root, options) {
393
+
394
+ var opts = serveOptions(root, options);
395
+ return function (req, res, next) {
396
+
397
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
398
+ if (opts.fallthrough)
399
+ return next()
400
+ return HTTP.NOT_ALLOWED(res);
401
+ }
402
+
403
+ const pathname = opts.root;
404
+ fs.stat(pathname, function onstat (err, stat) {
405
+ if (err)
406
+ return HTTP.INTERNAL_ERROR(res, err.code);
407
+ if (stat.isDirectory())
408
+ return HTTP.INTERNAL_ERROR(res, err.code);
409
+
410
+ sendFile(req, res, pathname, stat, opts)
411
+ });
412
+ }
413
+ }
386
414
 
387
415
 
388
- module.exports = serveStatic;
416
+ module.exports = { serveStatic, serveFile, sendFile, sendIndex };