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.
- package/README.md +2 -1
- package/index.js +57 -18
- package/package.json +1 -1
- 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
|
-
|
|
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
|
|
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
|
-
|
|
101
|
-
|
|
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
|
|
105
|
-
let key =
|
|
106
|
-
let val =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
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 (
|
|
257
|
-
return HTTP.PRECONDITION_FAILS(res)
|
|
258
|
-
}
|
|
256
|
+
if (conditionMatch(req.headers, res.getHeaders())) {
|
|
259
257
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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.
|
|
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
|
|
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:
|
|
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
|
-
|
|
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 };
|