Initial import from local backup (Documents-Playground/pakerpale)

This commit is contained in:
jeonghwa
2026-07-03 05:27:31 +09:00
commit 3a8de01ba0
1794 changed files with 137027 additions and 0 deletions

1
node_modules/beeline/.npmignore generated vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

241
node_modules/beeline/README.markdown generated vendored Normal file
View 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
View 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
View 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
View 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.");
});