Initial import from local backup (Documents-Playground/pakerpale)
This commit is contained in:
1
node_modules/beeline/.npmignore
generated
vendored
Normal file
1
node_modules/beeline/.npmignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
241
node_modules/beeline/README.markdown
generated
vendored
Normal file
241
node_modules/beeline/README.markdown
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
# Beeline
|
||||
|
||||
A laughably simplistic router for node.js
|
||||
|
||||
Currently works with node.js v0.3.1 and above
|
||||
|
||||
## Goals
|
||||
* Simple
|
||||
* Unobtrusive
|
||||
* Fairly Foolproof
|
||||
* Easy to debug
|
||||
* Fast
|
||||
|
||||
## Examples
|
||||
|
||||
```javascript
|
||||
var bee = require("beeline");
|
||||
var router = bee.route({ // Create a new router
|
||||
"/cheggit": function(req, res) {
|
||||
// Called when req.url === "/cheggit" or req.url === "/cheggit?woo=poo"
|
||||
},
|
||||
"/names/`last-name`/`first-name`": function(req, res, tokens, values) {
|
||||
// Called when req.url contains three parts, the first of is "name".
|
||||
// The parameter tokens is an object that maps token names to values.
|
||||
// For example if req.url === "/names/smith/will"
|
||||
// then tokens === { "first-name": "will", "last-name": "smith" }
|
||||
// and values === [ "will", "smith" ]
|
||||
// also req.params === tokens
|
||||
},
|
||||
"/static/`path...`": function(req, res, tokens, values) {
|
||||
// Called when req.url starts with "/static/"
|
||||
// The parameter tokens is an object that maps token name to a value
|
||||
// The parameter values is a list of
|
||||
// For example if req.url === "/static/pictures/actors/smith/will.jpg"
|
||||
// then tokens === { "path": "pictures/actors/smith/will.jpg" }
|
||||
// and values === [ "pictures/actors/smith/will.jpg" ]
|
||||
// also req.params === tokens
|
||||
},
|
||||
"/`user`/static/`path...`": function(req, res, tokens, values) {
|
||||
// Called when req.url contains at least three parts, the second of which
|
||||
// is "static".
|
||||
// The parameter tokens is an object that maps token names and value
|
||||
// For example if req.url === "/da-oozer/static/pictures/venkman.jpg"
|
||||
// then tokens === { "user": "da-oozer", "path": "pictures/venkman.jpg" }
|
||||
// and values === [ "da-oozer", "pictures/venkman.jpg" ]
|
||||
// also req.params === tokens
|
||||
},
|
||||
"/blogs/`user-id: [a-z]{2}-\\d{5}`/`post-id: \\d+`": function(
|
||||
req, res, tokens, values
|
||||
) {
|
||||
// Called when req.url starts with "/blogs/" and when the second and third
|
||||
// parts match /[a-z]{2}-\d{5}/ and /\d+/ respectiviely.
|
||||
// The parameter tokens is an object that maps token names and value
|
||||
// For example if req.url === "/blog/ab-12345/1783"
|
||||
// then tokens === { "user-id": "ab-12345", "post-id": "1783" }
|
||||
// and values === [ "ab-12345", "1783" ]
|
||||
// also req.params === tokens
|
||||
},
|
||||
"r`^/actors/([\\w]+)/([\\w]+)$`": function(req, res, matches) {
|
||||
// Called when req.url matches this regex: "^/actors/([\\w]+)/([\\w]+)$"
|
||||
// An array of captured groups is passed as the third parameter
|
||||
// For example if req.url === "/actors/smith/will"
|
||||
// then matches === [ "smith", "will" ]
|
||||
},
|
||||
"`404`": function(req, res) {
|
||||
// Called when no other route rule are matched
|
||||
//
|
||||
// This handler can later be called explicitly with router.missing
|
||||
},
|
||||
"`500`": function(req, res, err) {
|
||||
// Called when an exception is thrown by another router function
|
||||
// The error that caused the exception is passed as the third parameter
|
||||
// This _not_ guaranteed to catch all exceptions
|
||||
//
|
||||
// This handler can later be called explicitly with router.error
|
||||
}
|
||||
});
|
||||
|
||||
router.add({ // Use `.add` to append new rules to a router
|
||||
"/ /home r`^/index(.php|.html|.xhtml)?$`": function(req, res) {
|
||||
// Called when req.url === "/" or req.url === "/home"
|
||||
// or req.url matches this regex: ^/index(.php|.html|.xhtml)?$
|
||||
// (i.e. req.url === "/index.php" or req.url === "/index.html")
|
||||
// Note that any number of rules can be combined using a space.
|
||||
// All rules will call the same request handler when matched.
|
||||
},
|
||||
"/my-method": { // Method (aka verb) specific dispatch. Note case matters.
|
||||
"GET": function(req, res) {
|
||||
// Called when req.url === "/my-method" and req.method === "GET"
|
||||
},
|
||||
"POST PUT": function(req, res) {
|
||||
// Called when req.url === "/my-method" and
|
||||
// req.method === "POST" or req.method === "PUT"
|
||||
// Methods can be combined with a space like URL rules.
|
||||
},
|
||||
"any": function(req, res) {
|
||||
// Called when req.url === "/my-method" and req.method is not
|
||||
// "GET" or "POST"
|
||||
}
|
||||
},
|
||||
"`405`": function(req, res) {
|
||||
// Called when when a URL is specified but no corresponding method (aka verb)
|
||||
// matches. For example, this handler would be executed if the "any" catch
|
||||
// all wasn't specified in the handler above and req.method === "HEAD"
|
||||
//
|
||||
// This handler can later be called explicitly with router.missingVerb
|
||||
},
|
||||
"/explicit-calls": function(req, res) { // If necessary you can reroute requests
|
||||
if(url.parse(req.url).query["item-name"] === "unknown") {
|
||||
// Calls the 404 (aka missing) handler:
|
||||
return router.missing(req, res, this);
|
||||
// The last parameter is optional. It sets the this pointer in the
|
||||
// 404 handler.
|
||||
}
|
||||
|
||||
if(url.parse(req.url).query["item-name"] === "an-error") {
|
||||
// Calls the 500 (aka error) handler:
|
||||
return router.error(req, res, err, this);
|
||||
// The last parameter is optional. It sets the this pointer in the
|
||||
// 500 handler.
|
||||
}
|
||||
|
||||
// Do normal request handling
|
||||
}
|
||||
});
|
||||
|
||||
// Starts serve with routes defined above:
|
||||
require("http").createServer(router).listen(8001);
|
||||
```
|
||||
|
||||
See `test/test.js` for a working example.
|
||||
|
||||
## The API
|
||||
|
||||
To start, simply store the `beeline` library in a local variable:
|
||||
```javascript
|
||||
var bee = require("beeline");
|
||||
```
|
||||
The `beeline` library contains the following three methods:
|
||||
|
||||
- `bee.route(routes)`: Used to create a new router. It returns a function called `rtn_fn` that takes [ServerRequest](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerRequest) and [ServerResponse](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerResponse) objects as parameters. The `routes` parameter is an objects that maps rules to handlers. See examples section for more details.
|
||||
- `bee.staticFile(path, mimeType[, maxage=31536000])`: This is a utility method that is used to quickly expose static files. It returns a function called `rtn_fn` that takes [ServerRequest](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerRequest) and [ServerResponse](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerResponse) objects as parameters. When `rtn_fn` is called, the file contents located at `path` are served (via the ServerResponse) with the `Content-Type` set to the `mimeType` parameter. If the file at `path` does not exist a `404` is served. The optional `maxage` parameter is used to in the response's `Cache-Control` header. Also note that all `Set-Cookie` headers are removed. Here's an example of how you might use `bee.staticFile`:
|
||||
|
||||
```javascript
|
||||
bee.route({
|
||||
"/robots.txt": bee.staticFile("./content/robots.txt", "text/plain")
|
||||
});
|
||||
```
|
||||
- `bee.staticDir(path, mimeTypes[, maxage=31536000])`: This is utility method is used to expose directories of files. It returns a function called `rtn_fn` that takes a [ServerRequest](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerRequest) object, a [ServerResponse](http://nodejs.org/docs/v0.6.10/api/http.html#http.ServerResponse) object, an optional third parameter, and an array of strings called `matches` as parameters. Whenever `rtn_fn` is called, the items of `matches` are joined together and then concatenated to `path`. The resulting string is assumed to be a path to a specific file. If this file exists, its contents are served (via the ServerResponse) with the `Content-Type` set to the value that corresponds to the file's extension in the `mimeTypes` object. If the resulting string doesn't point to an existing file or if the file's extension is not found in `mimeTypes`, then a `404` is served. Also, file extensions require a leading period (`.`) and are assumed to be lowercase. The optional `maxage` parameter is used to in the response's `Cache-Control` header. Also note that all `Set-Cookie` headers are removed. Here's an example of how you might use `bee.staticDir`:
|
||||
|
||||
```javascript
|
||||
bee.route({
|
||||
// /pics/mofo.png serves ./content/pics/mofo.png
|
||||
// /pics/la-ghetto/oh-gee.gif serves ./content/pics/la-ghetto/oh-gee.gif
|
||||
// /pics/woo-fee.tiff serves a 404 since there's no corresponding
|
||||
// mimeType specified.
|
||||
// This helps prevent accidental exposure.
|
||||
"r`^/pics/(.*)$`": bee.staticDir(
|
||||
"./content/pics/",
|
||||
{
|
||||
".gif": "image/gif", ".png": "image/png",
|
||||
".jpg": "image/jpeg", ".jpeg": "image/jpeg"
|
||||
}
|
||||
),
|
||||
// Also works with URLs with tokens
|
||||
// /static/help/faq.html serves ./static/help/faq.html
|
||||
// /static/properties.json serves a 404 since there's no corresponding
|
||||
// mimeType specified.
|
||||
"/static/`path...`": bee.staticDir(
|
||||
"./static/",
|
||||
{
|
||||
".txt": "text/plain", ".html": "text/html",
|
||||
".css": "text/css", ".xml": "text/xml"
|
||||
}
|
||||
),
|
||||
// More complicated path constructs also works
|
||||
// /will-smith/img-library/headshots/sexy42.jpg
|
||||
// serves ./user-images/will-smith/headshots/sexy42.jpg
|
||||
"/`user`/img-library/`path...`": bee.staticDir(
|
||||
"./user-images/", { ".jpg": "image/jpeg", ".jpeg": "image/jpeg" }
|
||||
)
|
||||
});
|
||||
```
|
||||
|
||||
Beeline is also at least somewhat compatibile with [expressjs](https://github.com/visionmedia/express). Here's an example:
|
||||
|
||||
```javascript
|
||||
app.use(beeline.route({
|
||||
"/": function(req, res, next) {
|
||||
fs.readFile("./templates/index.html", function(err, data) {
|
||||
if(err) { throw err; }
|
||||
|
||||
res.html(data);
|
||||
});
|
||||
},
|
||||
"/`user`/static/`path...`": function(req, res, tokens, values, next) {
|
||||
/* ... code ... */
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
Note the `next` callback is always passed as the last parameter.
|
||||
|
||||
### Precedence Rules
|
||||
|
||||
In the event that a request matches two rules, the following precedence rules are considered:
|
||||
|
||||
- Fully defined rules take highest precedence. In other words, `"/index"` has a higher precedences then ``"r`^/index$`"`` even though semantically both rules are exactly the same.
|
||||
- Tokens and RegExp rules have the same precedence
|
||||
- RegExp rules take higher precedence than `404`
|
||||
- `404` and `405` have the lowest precedences
|
||||
- The `500` rules is outside the precedence rules. It can potentially be triggered at any time.
|
||||
- Amoung request methods, "any" has the lowerest precdence. Also note that the "x-http-method-override" header is respected.
|
||||
|
||||
If the exact same rule is defined twice, then it's unspecified which request handler will be triggered.
|
||||
|
||||
## Getting Beeline
|
||||
|
||||
The easiest way to get beeline is with [npm](http://npmjs.org/):
|
||||
|
||||
npm install beeline
|
||||
|
||||
Alternatively you can clone this git repository:
|
||||
|
||||
git clone git://github.com/xavi-/beeline.git
|
||||
|
||||
## Running Unit Tests
|
||||
|
||||
Execute the following commands to run the beeline's unit tests:
|
||||
|
||||
$ cd <beeline-directory>
|
||||
$ cd test
|
||||
$ node test.js
|
||||
|
||||
The last line printed to the console should be, "All done. Everything passed.", if all the tests passed successfully.
|
||||
|
||||
## Developed by
|
||||
* Xavi Ramirez
|
||||
|
||||
## License
|
||||
This project is released under [The MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
379
node_modules/beeline/index.js
generated
vendored
Normal file
379
node_modules/beeline/index.js
generated
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
var url = require("url");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var crypto = require("crypto");
|
||||
var lru = require("lru-cache");
|
||||
|
||||
var getBuffer = (function() {
|
||||
var buffers = lru({ max: 1024 * 500, length: function(n) { return n.length; } });
|
||||
|
||||
function watchBuffer(filePath) {
|
||||
if(buffers.has(filePath)) { return; }
|
||||
|
||||
buffers.del(filePath);
|
||||
fs.watchFile(filePath, function() { buffers.del(filePath); });
|
||||
}
|
||||
|
||||
return function getBuffer(filePath, callback) {
|
||||
if(buffers.has(filePath)) { return callback(null, buffers.get(filePath)); }
|
||||
|
||||
fs.stat(filePath, function(err, stats) {
|
||||
if(err && err.code === "ENOENT") {
|
||||
return callback({ "file-not-found": true, path: filePath }, null);
|
||||
}
|
||||
|
||||
if(err) { return callback(err, null); }
|
||||
|
||||
if(!stats.isFile()) {
|
||||
return callback({ "not-a-file": true, path: filePath }, null);
|
||||
}
|
||||
|
||||
fs.readFile(filePath, function(err, data) {
|
||||
if(err) { return callback(err, null); }
|
||||
|
||||
watchBuffer(filePath);
|
||||
buffers.set(filePath, {
|
||||
data: data,
|
||||
sum: crypto.createHash("sha1").update(data).digest("hex")
|
||||
});
|
||||
callback(null, buffers.get(filePath));
|
||||
});
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
function sendBuffer(req, res, mimeType, maxAge) {
|
||||
return function(err, buffer) {
|
||||
if(err) {
|
||||
if(err["file-not-found"]) {
|
||||
console.error("Could not find file: " + err.path);
|
||||
return default404(req, res);
|
||||
} else if(err["not-a-file"]) {
|
||||
console.error("Not a file: " + err.path);
|
||||
return default404(req, res);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
if(maxAge == null) { maxAge = 365 * 24 * 60 * 60; }
|
||||
|
||||
res.removeHeader("Set-Cookie");
|
||||
res.setHeader("Cache-Control", "private, max-age=" + maxAge);
|
||||
res.setHeader("ETag", buffer.sum);
|
||||
|
||||
if(req.headers["if-none-match"] === buffer.sum) {
|
||||
res.writeHead(304);
|
||||
return res.end();
|
||||
} else {
|
||||
res.writeHead(
|
||||
res.statusCode || 200,
|
||||
{ "Content-Length": buffer.data.length, "Content-Type": mimeType }
|
||||
);
|
||||
return res.end(buffer.data, "binary");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var staticFile = (function() {
|
||||
function handler(filePath, mimeType, req, res, maxAge) {
|
||||
getBuffer(filePath, sendBuffer(req, res, mimeType, maxAge));
|
||||
}
|
||||
|
||||
return function staticFile(filePath, mime, maxAge) {
|
||||
return function(req, res) { handler(filePath, mime, req, res, maxAge); };
|
||||
};
|
||||
})();
|
||||
|
||||
function staticDir(rootDir, mimeLookup, maxAge) {
|
||||
for(var key in mimeLookup) {
|
||||
if(key.charAt(0) !== ".") {
|
||||
console.warn("Extension found without a leading periond ('.'): '" + key + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return function(req, res, extra, matches) {
|
||||
matches = matches || extra;
|
||||
var filePath = path.join.apply(path, [ rootDir ].concat(matches));
|
||||
var ext = path.extname(filePath).toLowerCase();
|
||||
|
||||
if(!(ext in mimeLookup)) {
|
||||
console.error("Unknown file extension -- file: " + filePath + "; extension: " + ext);
|
||||
return default404(req, res);
|
||||
}
|
||||
|
||||
if(path.relative(rootDir, filePath).indexOf("..") !== -1) {
|
||||
console.error(
|
||||
"Attempted access to parent directory -- root: " + rootDir + "; subdir: " + filePath
|
||||
);
|
||||
return default404(req, res);
|
||||
}
|
||||
|
||||
getBuffer(filePath, sendBuffer(req, res, mimeLookup[ext], maxAge));
|
||||
};
|
||||
}
|
||||
|
||||
function default404(req, res, next) {
|
||||
if(next) { return next(); }
|
||||
|
||||
var body = "404'd";
|
||||
res.writeHead(404, { "Content-Length": body.length, "Content-Type": "text/plain" });
|
||||
res.end(body);
|
||||
|
||||
console.log("Someone 404'd: " + req.url);
|
||||
}
|
||||
function default405(req, res, next) {
|
||||
if(next) { return next(); }
|
||||
|
||||
var body = "405'd";
|
||||
res.writeHead(405, { "Content-Length": body.length, "Content-Type": "text/plain" });
|
||||
res.end(body);
|
||||
|
||||
console.log("Someone 405'd -- url: " + req.url + "; verb: " + req.method);
|
||||
}
|
||||
function default500(req, res, err, next) {
|
||||
if(next) { return next(err); }
|
||||
|
||||
console.error("Error accessing: " + req.method + " " + req.url);
|
||||
console.error(err.message);
|
||||
console.error(err.stack);
|
||||
|
||||
var body = [ "500'd" ];
|
||||
body.push("An exception was thrown while accessing: " + req.method + " " + req.url);
|
||||
body.push("Exception: " + err.message);
|
||||
body = body.join("\n");
|
||||
res.writeHead(500, { "Content-Length": body.length, "Content-Type": "text/plain" });
|
||||
res.end(body);
|
||||
}
|
||||
|
||||
function findPattern(patterns, urlPath) {
|
||||
for(var i = 0, l = patterns.length; i < l; i++) {
|
||||
if(patterns[i].regex.test(urlPath)) {
|
||||
return {
|
||||
handler: patterns[i].handler,
|
||||
extra: patterns[i].regex.exec(urlPath).slice(1)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function findGeneric(generics, req) {
|
||||
for(var i = 0, l = generics.length; i < l; i++) {
|
||||
if(generics[i].test(req)) { return generics[i].handler; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var rRegExUrl = /^r`(.*)`$/, rToken = /`(.*?)(?:(?:\:\s*(.*?))|(\.\.\.)?)`/g;
|
||||
function createTokenHandler(tokens, handler) {
|
||||
return function(req, res, oriVals, next) {
|
||||
var extra = Object.create(null);
|
||||
var newVals = new Array(tokens.length);
|
||||
for(var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
extra[token.name] = decodeURIComponent(oriVals[token.captureIdx]);
|
||||
newVals[i] = oriVals[token.captureIdx];
|
||||
}
|
||||
executeHandler(handler, this, req, res, { extra: extra, vals: newVals, next: next });
|
||||
};
|
||||
}
|
||||
var rHasFullCapture = /^\((?!\?[:!=]).*\)$/;
|
||||
function processEmbeddedRegex(regex) {
|
||||
regex = regex.trim();
|
||||
var rTest = new RegExp("|" + regex);
|
||||
var numCaptures = rTest.exec("").length - 1;
|
||||
|
||||
if(numCaptures <= 0) { return { regex: "(" + regex + ")", numCaptures: 1 }; }
|
||||
|
||||
if(rHasFullCapture.test(regex)) { return { regex: regex, numCaptures: numCaptures }; }
|
||||
|
||||
return { regex: "(" + regex + ")", numCaptures: numCaptures + 1 };
|
||||
}
|
||||
var rHasBackreference = /\\[1-9]/;
|
||||
function parseToken(rule, handler) {
|
||||
var tokens = [], captureIdx = 0;
|
||||
var transform = rule.replace(rToken, function replaceToken(_, name, regex, isExtend) {
|
||||
if(!regex) {
|
||||
tokens.push({ name: name, captureIdx: captureIdx });
|
||||
captureIdx += 1;
|
||||
} else {
|
||||
var info = processEmbeddedRegex(regex);
|
||||
regex = info.regex;
|
||||
tokens.push({ name: name, captureIdx: captureIdx });
|
||||
captureIdx += info.numCaptures;
|
||||
if(rHasBackreference.test(regex)) {
|
||||
console.warn("Backreference are not supported -- url: " + rule);
|
||||
}
|
||||
}
|
||||
return regex || (isExtend ? "(.*?)" : "([^/]*?)");
|
||||
});
|
||||
var rRule = new RegExp("^" + transform + "$");
|
||||
return { regex: rRule, handler: createTokenHandler(tokens, handler) };
|
||||
}
|
||||
|
||||
|
||||
function executeHandler(handler, thisp, req, res, opts) {
|
||||
var override = req.headers && req.headers["x-http-method-override"];
|
||||
handler = (handler[override] || handler[req.method] || handler.any || handler);
|
||||
|
||||
var extra = opts.extra, vals = opts.vals, next = opts.next;
|
||||
|
||||
if(extra && vals) { req.params = extra; }
|
||||
|
||||
if(next) {
|
||||
if(extra && vals) { handler.call(thisp, req, res, extra, vals, next); }
|
||||
else if(extra) { handler.call(thisp, req, res, extra, next); }
|
||||
else { handler.call(thisp, req, res, next); }
|
||||
} else {
|
||||
if(extra && vals) { handler.call(thisp, req, res, extra, vals); }
|
||||
else if(extra) { handler.call(thisp, req, res, extra); }
|
||||
else { handler.call(thisp, req, res); }
|
||||
}
|
||||
}
|
||||
function expandVerbs(handler) { // Expands "POST GET": handler to "POST": handler, "GET": handler
|
||||
if(handler.test) { // For `generic` type handlers
|
||||
handler.handler = expandVerbs(handler.handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
for(var key in handler) {
|
||||
key.split(/\s+/).forEach(function(method) {
|
||||
handler[method] = handler[key];
|
||||
});
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
var rWhitespace = /[\x20\t\r\n\f]/;
|
||||
function splitRules(key) {
|
||||
var rules = [];
|
||||
var isQuoted = false, isPrevSpace = false;
|
||||
|
||||
var ruleIdx = 0, curIdx = 0;
|
||||
while(curIdx < key.length) {
|
||||
var chr = key.charAt(curIdx);
|
||||
|
||||
if(chr === "`") { isQuoted = !isQuoted; curIdx += 1; continue; }
|
||||
if(isQuoted) { curIdx += 1; continue; }
|
||||
if(!rWhitespace.test(chr)) { curIdx += 1; continue; }
|
||||
|
||||
rules.push(key.substring(ruleIdx, curIdx));
|
||||
do { // consume whitespace
|
||||
curIdx += 1;
|
||||
chr = key.charAt(curIdx);
|
||||
} while(curIdx < key.length && rWhitespace.test(chr));
|
||||
ruleIdx = curIdx;
|
||||
}
|
||||
|
||||
if(isQuoted) { console.warn("Invalid beeline rule: " + key.substring(ruleIdx)); }
|
||||
else if(ruleIdx !== curIdx) { rules.push(key.substring(ruleIdx)); }
|
||||
|
||||
return rules;
|
||||
}
|
||||
function route(routes) {
|
||||
var preprocess = [], urls = Object.create(null), patterns = [], generics = [];
|
||||
var missing = default404, missingVerb = default405, error = default500;
|
||||
|
||||
function handler(req, res, next) {
|
||||
try {
|
||||
var urlPath = url.parse(req.url).pathname;
|
||||
var info = (
|
||||
urls[urlPath] ||
|
||||
findPattern(patterns, urlPath) ||
|
||||
findGeneric(generics, req) ||
|
||||
missing
|
||||
);
|
||||
var handler = info.handler || info;
|
||||
var extra = info.extra;
|
||||
|
||||
preprocess.forEach(function(process) { process(req, res); });
|
||||
|
||||
executeHandler(handler, this, req, res, { extra: extra, next: next });
|
||||
} catch(err) {
|
||||
error.call(this, req, res, err, next);
|
||||
}
|
||||
}
|
||||
function missingVerbHandler(req, res) {
|
||||
var next = arguments[arguments.length - 1];
|
||||
|
||||
if(typeof next !== "function") { missingVerb.call(this, req, res); }
|
||||
else { missingVerb.call(this, req, res, next); }
|
||||
}
|
||||
handler.add = function(routes) {
|
||||
for(var key in routes) {
|
||||
var handler = routes[key];
|
||||
|
||||
if(Object.prototype.toString.call(handler) === "[object Object]") {
|
||||
handler.any = handler.any || missingVerbHandler;
|
||||
}
|
||||
|
||||
if(key === "`preprocess`") {
|
||||
if(!Array.isArray(handler)) { preprocess.push(handler); }
|
||||
else { Array.prototype.push.apply(preprocess, handler); }
|
||||
continue;
|
||||
}
|
||||
|
||||
splitRules(key).forEach(function(rule) {
|
||||
if(rule.indexOf("`") === -1) {
|
||||
if(rule in urls) { console.warn("Duplicate beeline rule: " + rule); }
|
||||
if(rule.charAt(0) !== "/") {
|
||||
console.warn("Url doesn't have leading slash (/): " + rule);
|
||||
}
|
||||
urls[rule] = expandVerbs(handler);
|
||||
} else if(rule === "`404`" || rule === "`missing`" || rule === "`default`") {
|
||||
if(missing !== default404) { console.warn("Duplicate beeline rule: " + rule); }
|
||||
missing = expandVerbs(handler);
|
||||
} else if(
|
||||
rule === "`405`" || rule === "`missing-verb`" || rule === "`missingVerb`"
|
||||
) {
|
||||
if(missingVerb !== default405) {
|
||||
console.warn("Duplicate beeline rule: " + rule);
|
||||
}
|
||||
missingVerb = expandVerbs(handler);
|
||||
} else if(rule === "`500`" || rule === "`error`") {
|
||||
if(error !== default500) { console.warn("Duplicate beeline rule: " + rule); }
|
||||
error = expandVerbs(handler);
|
||||
} else if(rule === "`generics`") {
|
||||
Array.prototype.push.apply(generics, handler.map(expandVerbs));
|
||||
} else if(rRegExUrl.test(rule)) {
|
||||
var rRule = new RegExp(rRegExUrl.exec(rule)[1]);
|
||||
var cmpRegEx = function(p) { return p.regex.toString() === rRule.toString(); };
|
||||
if(patterns.some(cmpRegEx)) {
|
||||
console.warn("Duplicate beeline rule: " + rule);
|
||||
}
|
||||
patterns.push({ regex: rRule, handler: expandVerbs(handler) });
|
||||
} else if(rToken.test(rule)) {
|
||||
var pattern = parseToken(rule, expandVerbs(handler));
|
||||
var cmpPattern = function(p) {
|
||||
return p.regex.toString() === pattern.regex.toString();
|
||||
};
|
||||
if(patterns.some(cmpPattern)) {
|
||||
console.warn("Duplicate beeline rule: " + rule);
|
||||
}
|
||||
patterns.push(pattern);
|
||||
} else {
|
||||
console.warn("Invalid beeline rule: " + rule);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
handler.missing = function(req, res, thisp) {
|
||||
missing.call(thisp, req, res);
|
||||
};
|
||||
handler.missingVerb = function(req, res, thisp) {
|
||||
missingVerb.call(thisp, req, res);
|
||||
};
|
||||
handler.error = function(req, res, err, thisp) {
|
||||
error.call(thisp, req, res, err);
|
||||
};
|
||||
handler.add(routes);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
exports.route = route;
|
||||
exports.staticFile = staticFile;
|
||||
exports.staticDir = staticDir;
|
||||
60
node_modules/beeline/package.json
generated
vendored
Normal file
60
node_modules/beeline/package.json
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"_from": "beeline",
|
||||
"_id": "beeline@0.2.4",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-6Uh8V1PRyQQFuOI825GoaNDNsMw=",
|
||||
"_location": "/beeline",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "beeline",
|
||||
"name": "beeline",
|
||||
"escapedName": "beeline",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/beeline/-/beeline-0.2.4.tgz",
|
||||
"_shasum": "e9487c5753d1c90405b8e23cdb91a868d0cdb0cc",
|
||||
"_spec": "beeline",
|
||||
"_where": "D:\\dev\\xmap\\cm-oauth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/xavi-/beeline/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"lru-cache": "~2.3.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "A laughably simplistic router for node.js",
|
||||
"engines": {
|
||||
"node": ">= 0.3.1"
|
||||
},
|
||||
"homepage": "https://github.com/xavi-/beeline#readme",
|
||||
"keywords": [
|
||||
"url",
|
||||
"dispatch",
|
||||
"router",
|
||||
"request handler",
|
||||
"middleware"
|
||||
],
|
||||
"main": "./index.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Xavi",
|
||||
"email": "xavi.rmz@gmail.com",
|
||||
"url": "http://xavi.co"
|
||||
}
|
||||
],
|
||||
"name": "beeline",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/xavi-/beeline.git"
|
||||
},
|
||||
"version": "0.2.4"
|
||||
}
|
||||
523
node_modules/beeline/test/test.js
generated
vendored
Normal file
523
node_modules/beeline/test/test.js
generated
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
var assert = require("assert");
|
||||
var fs = require("fs");
|
||||
var crypto = require("crypto");
|
||||
var bee = require("../");
|
||||
|
||||
var tests = {
|
||||
expected: 74,
|
||||
executed: 0,
|
||||
finished: function() { tests.executed++; }
|
||||
};
|
||||
var warnings = {};
|
||||
console.warn = function(msg) { warnings[msg] = true; tests.finished(); };
|
||||
|
||||
var router = bee.route({
|
||||
"/test": function(req, res) { assert.equal(req.url, "/test?param=1&woo=2"); tests.finished(); },
|
||||
"/throw-error": function(req, res) { throw Error("500 should catch"); },
|
||||
"/names/`last-name`/`first-name`": function(req, res, tokens, vals) {
|
||||
assert.equal(req.url, "/names/smith/will");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["first-name"], "will");
|
||||
assert.equal(tokens["last-name"], "smith");
|
||||
assert.equal(vals[0], "smith");
|
||||
assert.equal(vals[1], "will");
|
||||
tests.finished();
|
||||
},
|
||||
"/static/`path...`": function(req, res, tokens, vals) {
|
||||
assert.equal(req.url, "/static/pictures/actors/smith/will.jpg");
|
||||
assert.equal(tokens["path"], "pictures/actors/smith/will.jpg");
|
||||
assert.equal(vals[0], "pictures/actors/smith/will.jpg");
|
||||
tests.finished();
|
||||
},
|
||||
"/`user`/static/`path...`": function(req, res, tokens, vals) {
|
||||
assert.equal(req.url, "/da-oozer/static/pictures/venkman.jpg");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["user"], "da-oozer");
|
||||
assert.equal(tokens["path"], "pictures/venkman.jpg");
|
||||
assert.equal(vals[0], "da-oozer");
|
||||
assert.equal(vals[1], "pictures/venkman.jpg");
|
||||
tests.finished();
|
||||
},
|
||||
"/`user`/profile": function(req, res, tokens, vals) { // Ensure tokens are decoded but not vals
|
||||
assert.equal(req.url, "/%E2%88%91%C3%A9%C3%B1/profile");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["user"], "∑éñ");
|
||||
assert.equal(vals[0], "%E2%88%91%C3%A9%C3%B1");
|
||||
tests.finished();
|
||||
},
|
||||
"r`^/actors/([\\w]+)/([\\w]+)$`": function(req, res, matches) {
|
||||
assert.equal(req.url, "/actors/smith/will");
|
||||
assert.equal(req.params, undefined);
|
||||
assert.equal(matches[0], "smith");
|
||||
assert.equal(matches[1], "will");
|
||||
tests.finished();
|
||||
},
|
||||
"`generics`": [ {
|
||||
test: function(req) { return req.triggerGeneric; },
|
||||
handler: function(req, res) {
|
||||
assert.equal(req.params, undefined);
|
||||
assert.ok(req.triggerGeneric); tests.finished();
|
||||
}
|
||||
}
|
||||
],
|
||||
"`404`": function(req, res) {
|
||||
assert.equal(req.url, "/url-not-found");
|
||||
tests.finished();
|
||||
},
|
||||
"`500`": function(req, res, err) {
|
||||
try { assert.equal(req.url, "/throw-error"); }
|
||||
catch(e) {
|
||||
console.error(e.stack);
|
||||
console.error("Caused by:");
|
||||
console.error(err.stack);
|
||||
process.exit();
|
||||
}
|
||||
assert.equal(err.message, "500 should catch");
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
router({ url: "/test?param=1&woo=2" });
|
||||
router({ url: "/throw-error" });
|
||||
router({ url: "/names/smith/will" });
|
||||
router({ url: "/static/pictures/actors/smith/will.jpg" });
|
||||
router({ url: "/da-oozer/static/pictures/venkman.jpg" });
|
||||
router({ url: "/%E2%88%91%C3%A9%C3%B1/profile" });
|
||||
router({ url: "/actors/smith/will" });
|
||||
router({ url: "/random", triggerGeneric: true });
|
||||
router({ url: "/url-not-found" });
|
||||
|
||||
router.add({
|
||||
"/ /home r`^/index(.php|.html|.xhtml)?$`": function(req, res) {
|
||||
assert.ok(
|
||||
req.url === "/" ||
|
||||
req.url === "/index" ||
|
||||
req.url === "/index.php" ||
|
||||
req.url === "/home"
|
||||
);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
router({ url: "/" });
|
||||
router({ url: "/index" });
|
||||
router({ url: "/index.php" });
|
||||
router({ url: "/home" });
|
||||
|
||||
router.add({
|
||||
"/method-test/`id`": {
|
||||
"GET": function(req, res) { assert.equal(req.method, "GET"); tests.finished(); },
|
||||
"POST": function(req, res) { assert.equal(req.method, "POST"); tests.finished(); },
|
||||
"any": function(req, res) {
|
||||
assert.ok(req.method !== "GET" || req.method !== "POST"); tests.finished();
|
||||
}
|
||||
},
|
||||
"/fake-put": {
|
||||
"PUT": function(req, res) {
|
||||
assert.equal(req.method, "GET");
|
||||
assert.equal(req.headers["x-http-method-override"], "PUT");
|
||||
tests.finished();
|
||||
},
|
||||
"any": function(req, res) { throw "I shouldn't have been called...."; }
|
||||
},
|
||||
"/`user`/profile/`path...`": {
|
||||
"POST PUT": function(req, res, tokens, vals) {
|
||||
assert.ok(req.method === "POST" || req.method === "PUT");
|
||||
tests.finished();
|
||||
}
|
||||
},
|
||||
"`405`": function(req, res) {
|
||||
assert.strictEqual(arguments.length, 2);
|
||||
assert.equal(req.method, "GET");
|
||||
assert.equal(req.url, "/dozer/profile/timeline/2010/holloween");
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
router({ url: "/method-test/123", method: "GET" });
|
||||
router({ url: "/method-test/123", method: "POST" });
|
||||
router({ url: "/method-test/123", method: "HEAD" });
|
||||
router({ url: "/fake-put", headers: { "x-http-method-override": "PUT" }, method: "GET" });
|
||||
router({ url: "/dozer/profile/timeline/2010/holloween", method: "POST" });
|
||||
router({ url: "/dozer/profile/timeline/2010/holloween", method: "PUT" });
|
||||
router({ url: "/dozer/profile/timeline/2010/holloween", method: "GET" });
|
||||
|
||||
// Testing preprocessors
|
||||
router.add({
|
||||
"`preprocess`": function(req, res) { req.foo = "bar"; res.bar = "baz"; },
|
||||
"/test-preprocess": function(req, res) {
|
||||
assert.equal(req.foo, "bar");
|
||||
assert.equal(res.bar, "baz");
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
router({ url: "/test-preprocess" }, {});
|
||||
|
||||
// Testing warning messages
|
||||
router.add({
|
||||
"/home": function() { },
|
||||
"no-slash": function() { },
|
||||
"r`^/actors/([\\w]+)/([\\w]+)$`": function() { },
|
||||
"/`user`/static/`path...`": function() { },
|
||||
"`404`": function() { },
|
||||
"`405`": function() { },
|
||||
"`500`": function() { },
|
||||
"`not-a-valid-rule": function() { },
|
||||
"/`not`/ok`": function() { },
|
||||
"/`not`/`ok-either": function() { },
|
||||
"/`backref: f(.)\\1`": function() { }
|
||||
});
|
||||
|
||||
assert.ok(warnings["Duplicate beeline rule: /home"]);
|
||||
assert.ok(warnings["Duplicate beeline rule: r`^/actors/([\\w]+)/([\\w]+)$`"]);
|
||||
assert.ok(warnings["Duplicate beeline rule: /`user`/static/`path...`"]);
|
||||
assert.ok(warnings["Duplicate beeline rule: `404`"]);
|
||||
assert.ok(warnings["Duplicate beeline rule: `405`"]);
|
||||
assert.ok(warnings["Duplicate beeline rule: `500`"]);
|
||||
assert.ok(warnings["Invalid beeline rule: `not-a-valid-rule"]);
|
||||
assert.ok(warnings["Invalid beeline rule: /`not`/ok`"]);
|
||||
assert.ok(warnings["Invalid beeline rule: /`not`/`ok-either"]);
|
||||
assert.ok(warnings["Backreference are not supported -- url: /`backref: f(.)\\1`"]);
|
||||
assert.ok(warnings["Url doesn't have leading slash (/): no-slash"]);
|
||||
|
||||
// Testing explicit 404, 405, and error calls
|
||||
var router2 = bee.route({
|
||||
"`404`": function(req, res) {
|
||||
assert.equal(req.url, "/explicit-404");
|
||||
assert.equal(res.isCorrectRequest, 1);
|
||||
assert.equal(this.extra, 1);
|
||||
tests.finished();
|
||||
},
|
||||
"`405`": function(req, res) {
|
||||
assert.equal(req.url, "/explicit-405");
|
||||
assert.equal(res.isCorrectRequest, 2);
|
||||
assert.equal(this.extra, 2);
|
||||
tests.finished();
|
||||
},
|
||||
"`500`": function(req, res, err) {
|
||||
assert.equal(req.url, "/explicit-500");
|
||||
assert.equal(res.isCorrectRequest, 3);
|
||||
assert.ok(err.isError);
|
||||
assert.equal(this.extra, 3);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
router2.missing({ url: "/explicit-404" }, { isCorrectRequest: 1 }, { extra: 1 });
|
||||
router2.missingVerb({ url: "/explicit-405" }, { isCorrectRequest: 2 }, { extra: 2 });
|
||||
router2.error({ url: "/explicit-500" }, { isCorrectRequest: 3 }, { isError: true }, { extra: 3 });
|
||||
|
||||
// Testing default 404, 405, and error handlers
|
||||
var route3 = bee.route();
|
||||
route3.missing({ request: true }, {
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 404);
|
||||
this.contentLength = headers["Content-Length"];
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.equal(this.contentLength, body.length);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
route3.missingVerb({ request: true }, {
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 405);
|
||||
this.contentLength = headers["Content-Length"];
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.equal(this.contentLength, body.length);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
route3.error({ request: true }, {
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 500);
|
||||
this.contentLength = headers["Content-Length"];
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.equal(this.contentLength, body.length);
|
||||
tests.finished();
|
||||
}
|
||||
}, {});
|
||||
|
||||
var staticFile = bee.staticFile("../index.js", "application/x-javascript");
|
||||
fs.readFile("../index.js", function(err, data) {
|
||||
if(err) { throw err; }
|
||||
|
||||
var isHeadWritten = false, setHeaders = {};
|
||||
staticFile({ headers: {}, url: "/load-existing-static-file" }, { // Mock response
|
||||
setHeader: function(type, val) {
|
||||
setHeaders[type] = val;
|
||||
},
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 200);
|
||||
assert.equal(headers["Content-Type"], "application/x-javascript");
|
||||
assert.equal(headers["Content-Length"], data.length);
|
||||
assert.ok(setHeaders["Cache-Control"]);
|
||||
assert.ok(setHeaders["ETag"]);
|
||||
tests.finished();
|
||||
isHeadWritten = true;
|
||||
},
|
||||
removeHeader: function(header) {
|
||||
assert.equal(header, "Set-Cookie");
|
||||
assert.ok(!isHeadWritten);
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.deepEqual(body, data);
|
||||
fs.unwatchFile("../index.js");
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var static404 = bee.staticFile("../does-not-exists", "not/real");
|
||||
static404({ url: "/load-non-existent-static-file" }, { // Mock response
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 404);
|
||||
assert.notEqual(headers["Content-Type"], "not/real");
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.ok(body);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
|
||||
var staticDir = bee.staticDir("../", {
|
||||
".json": "application/json", "js": "application/x-javascript"
|
||||
});
|
||||
assert.ok(warnings["Extension found without a leading periond ('.'): 'js'"]);
|
||||
fs.readFile("../package.json", function(err, data) {
|
||||
if(err) { throw err; }
|
||||
|
||||
var sum = crypto.createHash("sha1").update(data).digest("hex");
|
||||
|
||||
var isHeadWritten = false, setHeaders = {};
|
||||
staticDir({ headers: {}, url: "/load-existing-file-from-static-dir" }, {
|
||||
// Mock response of an empty cache
|
||||
setHeader: function(type, val) {
|
||||
setHeaders[type] = val;
|
||||
},
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 200);
|
||||
assert.equal(headers["Content-Type"], "application/json");
|
||||
assert.equal(headers["Content-Length"], data.length);
|
||||
assert.ok(setHeaders["Cache-Control"]);
|
||||
assert.equal(setHeaders["ETag"], sum);
|
||||
tests.finished();
|
||||
isHeadWritten = true;
|
||||
},
|
||||
removeHeader: function(header) {
|
||||
assert.equal(header, "Set-Cookie");
|
||||
assert.ok(!isHeadWritten);
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.deepEqual(body, data);
|
||||
fs.unwatchFile("../package.json"); // Internally beelines watches files for changes
|
||||
tests.finished();
|
||||
}
|
||||
}, [ "package.json" ]);
|
||||
});
|
||||
fs.readFile("../package.json", function(err, data) {
|
||||
if(err) { throw err; }
|
||||
|
||||
var sum = crypto.createHash("sha1").update(data).digest("hex");
|
||||
|
||||
var isHeadWritten = false, setHeaders = {};
|
||||
staticDir({ headers: { "if-none-match": sum }, url: "/do-304s-work" }, {
|
||||
// Mock cached response
|
||||
setHeader: function(type, val) {
|
||||
setHeaders[type] = val;
|
||||
},
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 304);
|
||||
assert.ok(setHeaders["Cache-Control"]);
|
||||
assert.equal(setHeaders["ETag"], sum);
|
||||
tests.finished();
|
||||
isHeadWritten = true;
|
||||
},
|
||||
removeHeader: function(header) {
|
||||
assert.equal(header, "Set-Cookie");
|
||||
assert.ok(!isHeadWritten);
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.ok(!body); // Ensure an empty body was sent
|
||||
fs.unwatchFile("../package.json"); // Internally beelines watches files for changes
|
||||
tests.finished();
|
||||
}
|
||||
}, [ "package.json" ]);
|
||||
});
|
||||
fs.readFile("../package.json", function(err, data) {
|
||||
if(err) { throw err; }
|
||||
|
||||
var isHeadWritten = false, setHeaders = {};
|
||||
staticDir({ headers: {}, url: "/called-with-optional-3rd-param" }, { // Mock response
|
||||
setHeader: function(type, val) { },
|
||||
writeHead: function(status, headers) { },
|
||||
removeHeader: function(header) { },
|
||||
end: function(body) {
|
||||
assert.deepEqual(body, data);
|
||||
fs.unwatchFile("../package.json"); // Internally beelines watches files for changes
|
||||
tests.finished();
|
||||
}
|
||||
}, { optional: "third parameter" }, [ "package.json" ]); // Called with optional third parameter
|
||||
});
|
||||
staticDir({ url: "/load-unrecognized-file-extension" }, { // Mock response
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 404);
|
||||
assert.ok(headers["Content-Type"]);
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.ok(body);
|
||||
tests.finished();
|
||||
}
|
||||
}, [ "README.markdown" ]);
|
||||
|
||||
staticDir({ url: "/attempt-to-insecurely-access-parent-directory" }, { // Mock response
|
||||
writeHead: function(status, headers) {
|
||||
assert.equal(status, 404);
|
||||
assert.ok(headers["Content-Type"]);
|
||||
tests.finished();
|
||||
},
|
||||
end: function(body) {
|
||||
assert.ok(body);
|
||||
tests.finished();
|
||||
}
|
||||
}, [ "..", "..", "ok.json" ]);
|
||||
|
||||
// Testing express compatibility
|
||||
var router4 = bee.route({
|
||||
"/throw-error": function(req, res, next) { throw Error("500 should catch"); }
|
||||
});
|
||||
router4({ url: "/unknown-url" }, {}, function next() {
|
||||
tests.finished();
|
||||
});
|
||||
router4({ url: "/throw-error" }, {}, function next(err) {
|
||||
assert.equal(err.message, "500 should catch");
|
||||
tests.finished();
|
||||
});
|
||||
|
||||
var daNext = function() {};
|
||||
router4.add({
|
||||
"/test": function(req, res, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"/test/`id`": {
|
||||
"GET": function() { throw Error("This shouldn't be called"); }
|
||||
},
|
||||
"/names/`last-name`/`first-name`": function(req, res, tokens, vals, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"/static/`path...`": function(req, res, tokens, vals, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"/`user`/static/`path...`": function(req, res, tokens, vals, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"r`^/actors/([\\w]+)/([\\w]+)$`": function(req, res, matches, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"`generics`": [ {
|
||||
test: function(req) { return req.triggerGeneric; },
|
||||
handler: function(req, res, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
}
|
||||
} ],
|
||||
"`404`": function(req, res, next) {
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"`405`": function(req, res, next) {
|
||||
assert.strictEqual(arguments.length, 3);
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
},
|
||||
"`500`": function(req, res, err, next) {
|
||||
try { assert.equal(req.url, "/throw-error"); }
|
||||
catch(e) {
|
||||
console.error(e.stack);
|
||||
console.error("Caused by:");
|
||||
console.error(err.stack);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
assert.strictEqual(next, daNext);
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
|
||||
router4({ url: "/test?param=1&woo=2" }, {}, daNext);
|
||||
router4({ url: "/throw-error" }, {}, daNext);
|
||||
router4({ url: "/names/smith/will" }, {}, daNext);
|
||||
router4({ url: "/actors/smith/will" }, {}, daNext);
|
||||
router4({ url: "/da-oozer/static/pictures/venkman.jpg" }, {}, daNext);
|
||||
router4({ url: "/static/pictures/actors/smith/will.jpg" }, {}, daNext);
|
||||
router4({ url: "/random", triggerGeneric: true }, {}, daNext);
|
||||
router4({ url: "/url-not-found" }, {}, daNext);
|
||||
router4({ url: "/test/123", method: "POST" }, {}, daNext);
|
||||
|
||||
// Test regex tokens
|
||||
var router5 = bee.route({
|
||||
"/`game`/`user-id:([a-z]{2}-\\d{5})`/`post-id:\\d+`/`file...`": function(
|
||||
req, res, tokens, vals
|
||||
) {
|
||||
assert.equal(req.url, "/space-wars/ab-12345/1943/pics/friends/will-smith.jpeg");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["game"], "space-wars");
|
||||
assert.equal(tokens["user-id"], "ab-12345");
|
||||
assert.equal(tokens["post-id"], "1943");
|
||||
assert.equal(tokens["file"], "pics/friends/will-smith.jpeg");
|
||||
assert.equal(vals[0], "space-wars");
|
||||
assert.equal(vals[1], "ab-12345");
|
||||
assert.equal(vals[2], "1943");
|
||||
assert.equal(vals[3], "pics/friends/will-smith.jpeg");
|
||||
tests.finished();
|
||||
},
|
||||
"/`foo: foo(?=/bar)`/`rest...`": function(req, res, tokens, vals) {
|
||||
assert.equal(req.url, "/foo/bar");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["foo"], "foo");
|
||||
assert.equal(tokens["rest"], "bar");
|
||||
assert.equal(vals[0], "foo");
|
||||
assert.equal(vals[1], "bar");
|
||||
tests.finished();
|
||||
},
|
||||
"/`foo: foo(?!/bar).*`": function(req, res, tokens, vals) {
|
||||
assert.equal(req.url, "/foo-king");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["foo"], "foo-king");
|
||||
assert.equal(vals[0], "foo-king");
|
||||
tests.finished();
|
||||
},
|
||||
"/`sum-space: ((((spacey)))) `/rule /another-spacey-rule ": function(
|
||||
req, res, tokens, vals
|
||||
) {
|
||||
if(req.url === "/another-spacey-rule") { tests.finished(); return; }
|
||||
|
||||
assert.equal(req.url, "/spacey/rule");
|
||||
assert.equal(tokens, req.params);
|
||||
assert.equal(tokens["sum-space"], "spacey");
|
||||
assert.equal(vals[0], "spacey");
|
||||
tests.finished();
|
||||
}
|
||||
});
|
||||
|
||||
router5({ url: "/space-wars/ab-12345/1943/pics/friends/will-smith.jpeg" });
|
||||
router5({ url: "/foo/bar" });
|
||||
router5({ url: "/foo-king" });
|
||||
router5({ url: "/spacey/rule" });
|
||||
router5({ url: "/another-spacey-rule" });
|
||||
|
||||
process.on("exit", function() {
|
||||
assert.equal(tests.executed, tests.expected);
|
||||
console.log("\n\nAll done. Everything passed.");
|
||||
});
|
||||
Reference in New Issue
Block a user