debugging

This commit is contained in:
Martin Donnelly 2016-02-12 13:10:16 +00:00
parent 7703b06f10
commit 9e83bbf956
1536 changed files with 12585 additions and 190648 deletions

38
.gitignore vendored
View File

@ -1,7 +1,43 @@
/node_modules/
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
.idea
/html/jobs-local.html
/html/jobs-local.xml
/html/lifestyle.xml
/html/paleo.html
/html/paleo.json
/html/paleo.xml

View File

@ -1,9 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="bin\www" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="C:/Program Files/nodejs/node" path-to-js-file="bin/www" working-dir="$PROJECT_DIR$">
<envs>
<env name="DEBUG" value="rinser:*" />
</envs>
<browser url="http://localhost:3000/" />
<method />
</configuration>
</component>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,7 @@ var braider_options = {
var rss_braider = RssBraider.createClient(braider_options);
// Override logging level (debug, info, warn, err, off)
rss_braider.logger.level('off');
//rss_braider.logger.level('off');
// Output braided feed as rss. use 'json' for JSON output.
rss_braider.processFeed('simple_test_feed', 'rss', function(err, data){

View File

@ -183,7 +183,7 @@ var braider_options = {
var rss_braider = RssBraider.createClient(braider_options);
// Override logging level (debug, info, warn, err, off)
rss_braider.logger.level('off');
//rss_braider.logger.level('off');
rss_braider.processFeed('simple_test_feed', 'json', function (err, data) {
if (err) {

View File

@ -100,7 +100,7 @@ var braider_options = {
var rss_braider = RssBraider.createClient(braider_options);
// Override logging level (debug, info, warn, err, off)
rss_braider.logger.level('off');
//rss_braider.logger.level('off');
rss_braider.processFeed('simple_test_feed', 'json', function(err, data) {
if (err) {

7
node_modules/ejs/README.md generated vendored
View File

@ -16,7 +16,8 @@ $ npm install ejs
* Control flow with `<% %>`
* Escaped output with `<%= %>`
* Unescaped raw output with `<%- %>`
* Trim-mode ('newline slurping') with `-%>` ending tag
* Newline-trim mode ('newline slurping') with `-%>` ending tag
* Whitespace-trim mode (slurp all whitespace) for control flow with `<%_ _%>`
* Custom delimiters (e.g., use '<? ?>' instead of '<% %>')
* Includes
* Client-side support
@ -56,7 +57,9 @@ for all the passed options.
- `client` Returns standalone compiled function
- `delimiter` Character to use with angle brackets for open/close
- `debug` Output generated function body
- `_with` Whether or not to use `with() {}` constructs. If `false` then the locals will be stored in the `locals` object.
- `strict` When set to `true`, generated function is in strict mode
- `_with` Whether or not to use `with() {}` constructs. If `false` then the locals will be stored in the `locals` object. Set to `false` in strict mode.
- `localsName` Name to use for the object storing local variables when not using `with` Defaults to `locals`
- `rmWhitespace` Remove all safe-to-remove whitespace, including leading
and trailing whitespace. It also enables a safer version of `-%>` line
slurping for all scriptlet tags (it does not strip new lines of tags in

41
node_modules/ejs/ejs.js generated vendored
View File

@ -54,6 +54,7 @@ var fs = require('fs')
, _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)'
, _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context'
, 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace'
, 'strict', 'localsName'
]
, _TRAILING_SEMCOL = /;\s*$/
, _BOM = /^\uFEFF/;
@ -343,7 +344,14 @@ exports.renderFile = function () {
// No options object -- if there are optiony names
// in the data, copy them to options
if (arguments.length == 3) {
cpOptsInData(data, opts);
// Express 4
if (data.settings && data.settings['view options']) {
cpOptsInData(data.settings['view options'], opts);
}
// Express 3 and lower
else {
cpOptsInData(data, opts);
}
}
opts.filename = path;
@ -380,10 +388,19 @@ function Template(text, opts) {
options.debug = !!opts.debug;
options.filename = opts.filename;
options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
options._with = typeof opts._with != 'undefined' ? opts._with : true;
options.strict = opts.strict || false;
options.context = opts.context;
options.cache = opts.cache || false;
options.rmWhitespace = opts.rmWhitespace;
options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
if (options.strict) {
options._with = false;
}
else {
options._with = typeof opts._with != 'undefined' ? opts._with : true;
}
this.opts = options;
this.regex = this.createRegex();
@ -428,7 +445,7 @@ Template.prototype = {
this.generateSource();
prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n';
if (opts._with !== false) {
prepended += ' with (' + exports.localsName + ' || {}) {' + '\n';
prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
appended += ' }' + '\n';
}
appended += ' return __output.join("");' + '\n';
@ -461,8 +478,12 @@ Template.prototype = {
}
}
if (opts.strict) {
src = '"use strict";\n' + src;
}
try {
fn = new Function(exports.localsName + ', escape, include, rethrow', src);
fn = new Function(opts.localsName + ', escape, include, rethrow', src);
}
catch(e) {
// istanbul ignore else
@ -577,11 +598,16 @@ Template.prototype = {
function _addOutput() {
if (self.truncate) {
line = line.replace('\n', '');
// Only replace single leading linebreak in the line after
// -%> tag -- this is the single, trailing linebreak
// after the tag that the truncation mode replaces
// Handle Win / Unix / old Mac linebreaks -- do the \r\n
// combo first in the regex-or
line = line.replace(/^(?:\r\n|\r|\n)/, '')
self.truncate = false;
}
else if (self.opts.rmWhitespace) {
// Gotta me more careful here.
// Gotta be more careful here.
// .replace(/^(\s*)\n/, '$1') might be more appropriate here but as
// rmWhitespace already removes trailing spaces anyway so meh.
line = line.replace(/^\n/, '');
@ -1164,7 +1190,7 @@ module.exports={
"engine",
"ejs"
],
"version": "2.3.3",
"version": "2.4.0",
"author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
"contributors": [
"Timothy Gu <timothygu99@gmail.com> (https://timothygu.github.io)"
@ -1198,4 +1224,5 @@ module.exports={
"devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*"
}
}
},{}]},{},[1]);

2
node_modules/ejs/ejs.min.js generated vendored

File diff suppressed because one or more lines are too long

38
node_modules/ejs/lib/ejs.js generated vendored
View File

@ -53,6 +53,7 @@ var fs = require('fs')
, _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)'
, _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context'
, 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace'
, 'strict', 'localsName'
]
, _TRAILING_SEMCOL = /;\s*$/
, _BOM = /^\uFEFF/;
@ -342,7 +343,14 @@ exports.renderFile = function () {
// No options object -- if there are optiony names
// in the data, copy them to options
if (arguments.length == 3) {
cpOptsInData(data, opts);
// Express 4
if (data.settings && data.settings['view options']) {
cpOptsInData(data.settings['view options'], opts);
}
// Express 3 and lower
else {
cpOptsInData(data, opts);
}
}
opts.filename = path;
@ -379,10 +387,19 @@ function Template(text, opts) {
options.debug = !!opts.debug;
options.filename = opts.filename;
options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
options._with = typeof opts._with != 'undefined' ? opts._with : true;
options.strict = opts.strict || false;
options.context = opts.context;
options.cache = opts.cache || false;
options.rmWhitespace = opts.rmWhitespace;
options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
if (options.strict) {
options._with = false;
}
else {
options._with = typeof opts._with != 'undefined' ? opts._with : true;
}
this.opts = options;
this.regex = this.createRegex();
@ -427,7 +444,7 @@ Template.prototype = {
this.generateSource();
prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n';
if (opts._with !== false) {
prepended += ' with (' + exports.localsName + ' || {}) {' + '\n';
prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
appended += ' }' + '\n';
}
appended += ' return __output.join("");' + '\n';
@ -460,8 +477,12 @@ Template.prototype = {
}
}
if (opts.strict) {
src = '"use strict";\n' + src;
}
try {
fn = new Function(exports.localsName + ', escape, include, rethrow', src);
fn = new Function(opts.localsName + ', escape, include, rethrow', src);
}
catch(e) {
// istanbul ignore else
@ -576,11 +597,16 @@ Template.prototype = {
function _addOutput() {
if (self.truncate) {
line = line.replace('\n', '');
// Only replace single leading linebreak in the line after
// -%> tag -- this is the single, trailing linebreak
// after the tag that the truncation mode replaces
// Handle Win / Unix / old Mac linebreaks -- do the \r\n
// combo first in the regex-or
line = line.replace(/^(?:\r\n|\r|\n)/, '')
self.truncate = false;
}
else if (self.opts.rmWhitespace) {
// Gotta me more careful here.
// Gotta be more careful here.
// .replace(/^(\s*)\n/, '$1') might be more appropriate here but as
// rmWhitespace already removes trailing spaces anyway so meh.
line = line.replace(/^\n/, '');

104
node_modules/ejs/package.json generated vendored
View File

@ -1,17 +1,46 @@
{
"name": "ejs",
"description": "Embedded JavaScript templates",
"keywords": [
"template",
"engine",
"ejs"
"_args": [
[
"ejs@^2.3.3",
"C:\\mddev\\rinser"
]
],
"version": "2.3.4",
"author": {
"name": "Matthew Eernisse",
"_from": "ejs@>=2.3.3 <3.0.0",
"_id": "ejs@2.4.1",
"_inCache": true,
"_installable": true,
"_location": "/ejs",
"_nodeVersion": "0.12.4",
"_npmUser": {
"email": "mde@fleegix.org",
"name": "mde"
},
"_npmVersion": "2.10.1",
"_phantomChildren": {},
"_requested": {
"name": "ejs",
"raw": "ejs@^2.3.3",
"rawSpec": "^2.3.3",
"scope": null,
"spec": ">=2.3.3 <3.0.0",
"type": "range"
},
"_requiredBy": [
"#DEV:/"
],
"_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz",
"_shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566",
"_shrinkwrap": null,
"_spec": "ejs@^2.3.3",
"_where": "C:\\mddev\\rinser",
"author": {
"email": "mde@fleegix.org",
"name": "Matthew Eernisse",
"url": "http://fleegix.org"
},
"bugs": {
"url": "https://github.com/mde/ejs/issues"
},
"contributors": [
{
"name": "Timothy Gu",
@ -19,17 +48,8 @@
"url": "https://timothygu.github.io"
}
],
"license": "Apache-2.0",
"main": "./lib/ejs.js",
"repository": {
"type": "git",
"url": "git://github.com/mde/ejs.git"
},
"bugs": {
"url": "https://github.com/mde/ejs/issues"
},
"homepage": "https://github.com/mde/ejs",
"dependencies": {},
"description": "Embedded JavaScript templates",
"devDependencies": {
"browserify": "^8.0.3",
"istanbul": "~0.3.5",
@ -40,25 +60,22 @@
"rimraf": "^2.2.8",
"uglify-js": "^2.4.16"
},
"directories": {},
"dist": {
"shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566",
"tarball": "http://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "mocha",
"coverage": "istanbul cover node_modules/mocha/bin/_mocha",
"doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*",
"devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*"
},
"_id": "ejs@2.3.4",
"_shasum": "3c76caa09664b3583b0037af9dc136e79ec68b98",
"_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.3.4.tgz",
"_from": "ejs@>=2.3.3 <3.0.0",
"_npmVersion": "2.10.1",
"_nodeVersion": "0.12.4",
"_npmUser": {
"name": "mde",
"email": "mde@fleegix.org"
},
"homepage": "https://github.com/mde/ejs",
"keywords": [
"ejs",
"engine",
"template"
],
"license": "Apache-2.0",
"main": "./lib/ejs.js",
"maintainers": [
{
"name": "tjholowaychuk",
@ -69,9 +86,18 @@
"email": "mde@fleegix.org"
}
],
"dist": {
"shasum": "3c76caa09664b3583b0037af9dc136e79ec68b98",
"tarball": "http://registry.npmjs.org/ejs/-/ejs-2.3.4.tgz"
"name": "ejs",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/mde/ejs.git"
},
"directories": {}
"scripts": {
"coverage": "istanbul cover node_modules/mocha/bin/_mocha",
"devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*",
"doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*",
"test": "mocha"
},
"version": "2.4.1"
}

28
node_modules/ejs/test/ejs.js generated vendored
View File

@ -511,6 +511,34 @@ suite('-%>', function () {
}
throw new Error('Expected ReferenceError');
});
test('works with unix style', function () {
var content = "<ul><% -%>\n"
+ "<% users.forEach(function(user){ -%>\n"
+ "<li><%= user.name -%></li>\n"
+ "<% }) -%>\n"
+ "</ul><% -%>\n";
var expectedResult = "<ul><li>geddy</li>\n<li>neil</li>\n<li>alex</li>\n</ul>";
var fn;
fn = ejs.compile(content);
assert.equal(fn({users: users}),
expectedResult);
});
test('works with windows style', function () {
var content = "<ul><% -%>\r\n"
+ "<% users.forEach(function(user){ -%>\r\n"
+ "<li><%= user.name -%></li>\r\n"
+ "<% }) -%>\r\n"
+ "</ul><% -%>\r\n";
var expectedResult = "<ul><li>geddy</li>\r\n<li>neil</li>\r\n<li>alex</li>\r\n</ul>";
var fn;
fn = ejs.compile(content);
assert.equal(fn({users: users}),
expectedResult);
});
});
suite('<%%', function () {

927
node_modules/express/History.md generated vendored
View File

@ -1,3 +1,925 @@
4.13.4 / 2016-01-21
===================
* deps: content-disposition@0.5.1
- perf: enable strict mode
* deps: cookie@0.1.5
- Throw on invalid values provided to `serialize`
* deps: depd@~1.1.0
- Support web browser loading
- perf: enable strict mode
* deps: escape-html@~1.0.3
- perf: enable strict mode
- perf: optimize string replacement
- perf: use faster string coercion
* deps: finalhandler@0.4.1
- deps: escape-html@~1.0.3
* deps: merge-descriptors@1.0.1
- perf: enable strict mode
* deps: methods@~1.1.2
- perf: enable strict mode
* deps: parseurl@~1.3.1
- perf: enable strict mode
* deps: proxy-addr@~1.0.10
- deps: ipaddr.js@1.0.5
- perf: enable strict mode
* deps: range-parser@~1.0.3
- perf: enable strict mode
* deps: send@0.13.1
- deps: depd@~1.1.0
- deps: destroy@~1.0.4
- deps: escape-html@~1.0.3
- deps: range-parser@~1.0.3
* deps: serve-static@~1.10.2
- deps: escape-html@~1.0.3
- deps: parseurl@~1.3.0
- deps: send@0.13.1
4.13.3 / 2015-08-02
===================
* Fix infinite loop condition using `mergeParams: true`
* Fix inner numeric indices incorrectly altering parent `req.params`
4.13.2 / 2015-07-31
===================
* deps: accepts@~1.2.12
- deps: mime-types@~2.1.4
* deps: array-flatten@1.1.1
- perf: enable strict mode
* deps: path-to-regexp@0.1.7
- Fix regression with escaped round brackets and matching groups
* deps: type-is@~1.6.6
- deps: mime-types@~2.1.4
4.13.1 / 2015-07-05
===================
* deps: accepts@~1.2.10
- deps: mime-types@~2.1.2
* deps: qs@4.0.0
- Fix dropping parameters like `hasOwnProperty`
- Fix various parsing edge cases
* deps: type-is@~1.6.4
- deps: mime-types@~2.1.2
- perf: enable strict mode
- perf: remove argument reassignment
4.13.0 / 2015-06-20
===================
* Add settings to debug output
* Fix `res.format` error when only `default` provided
* Fix issue where `next('route')` in `app.param` would incorrectly skip values
* Fix hiding platform issues with `decodeURIComponent`
- Only `URIError`s are a 400
* Fix using `*` before params in routes
* Fix using capture groups before params in routes
* Simplify `res.cookie` to call `res.append`
* Use `array-flatten` module for flattening arrays
* deps: accepts@~1.2.9
- deps: mime-types@~2.1.1
- perf: avoid argument reassignment & argument slice
- perf: avoid negotiator recursive construction
- perf: enable strict mode
- perf: remove unnecessary bitwise operator
* deps: cookie@0.1.3
- perf: deduce the scope of try-catch deopt
- perf: remove argument reassignments
* deps: escape-html@1.0.2
* deps: etag@~1.7.0
- Always include entity length in ETags for hash length extensions
- Generate non-Stats ETags using MD5 only (no longer CRC32)
- Improve stat performance by removing hashing
- Improve support for JXcore
- Remove base64 padding in ETags to shorten
- Support "fake" stats objects in environments without fs
- Use MD5 instead of MD4 in weak ETags over 1KB
* deps: finalhandler@0.4.0
- Fix a false-positive when unpiping in Node.js 0.8
- Support `statusCode` property on `Error` objects
- Use `unpipe` module for unpiping requests
- deps: escape-html@1.0.2
- deps: on-finished@~2.3.0
- perf: enable strict mode
- perf: remove argument reassignment
* deps: fresh@0.3.0
- Add weak `ETag` matching support
* deps: on-finished@~2.3.0
- Add defined behavior for HTTP `CONNECT` requests
- Add defined behavior for HTTP `Upgrade` requests
- deps: ee-first@1.1.1
* deps: path-to-regexp@0.1.6
* deps: send@0.13.0
- Allow Node.js HTTP server to set `Date` response header
- Fix incorrectly removing `Content-Location` on 304 response
- Improve the default redirect response headers
- Send appropriate headers on default error response
- Use `http-errors` for standard emitted errors
- Use `statuses` instead of `http` module for status messages
- deps: escape-html@1.0.2
- deps: etag@~1.7.0
- deps: fresh@0.3.0
- deps: on-finished@~2.3.0
- perf: enable strict mode
- perf: remove unnecessary array allocations
* deps: serve-static@~1.10.0
- Add `fallthrough` option
- Fix reading options from options prototype
- Improve the default redirect response headers
- Malformed URLs now `next()` instead of 400
- deps: escape-html@1.0.2
- deps: send@0.13.0
- perf: enable strict mode
- perf: remove argument reassignment
* deps: type-is@~1.6.3
- deps: mime-types@~2.1.1
- perf: reduce try block size
- perf: remove bitwise operations
* perf: enable strict mode
* perf: isolate `app.render` try block
* perf: remove argument reassignments in application
* perf: remove argument reassignments in request prototype
* perf: remove argument reassignments in response prototype
* perf: remove argument reassignments in routing
* perf: remove argument reassignments in `View`
* perf: skip attempting to decode zero length string
* perf: use saved reference to `http.STATUS_CODES`
4.12.4 / 2015-05-17
===================
* deps: accepts@~1.2.7
- deps: mime-types@~2.0.11
- deps: negotiator@0.5.3
* deps: debug@~2.2.0
- deps: ms@0.7.1
* deps: depd@~1.0.1
* deps: etag@~1.6.0
- Improve support for JXcore
- Support "fake" stats objects in environments without `fs`
* deps: finalhandler@0.3.6
- deps: debug@~2.2.0
- deps: on-finished@~2.2.1
* deps: on-finished@~2.2.1
- Fix `isFinished(req)` when data buffered
* deps: proxy-addr@~1.0.8
- deps: ipaddr.js@1.0.1
* deps: qs@2.4.2
- Fix allowing parameters like `constructor`
* deps: send@0.12.3
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: etag@~1.6.0
- deps: ms@0.7.1
- deps: on-finished@~2.2.1
* deps: serve-static@~1.9.3
- deps: send@0.12.3
* deps: type-is@~1.6.2
- deps: mime-types@~2.0.11
4.12.3 / 2015-03-17
===================
* deps: accepts@~1.2.5
- deps: mime-types@~2.0.10
* deps: debug@~2.1.3
- Fix high intensity foreground color for bold
- deps: ms@0.7.0
* deps: finalhandler@0.3.4
- deps: debug@~2.1.3
* deps: proxy-addr@~1.0.7
- deps: ipaddr.js@0.1.9
* deps: qs@2.4.1
- Fix error when parameter `hasOwnProperty` is present
* deps: send@0.12.2
- Throw errors early for invalid `extensions` or `index` options
- deps: debug@~2.1.3
* deps: serve-static@~1.9.2
- deps: send@0.12.2
* deps: type-is@~1.6.1
- deps: mime-types@~2.0.10
4.12.2 / 2015-03-02
===================
* Fix regression where `"Request aborted"` is logged using `res.sendFile`
4.12.1 / 2015-03-01
===================
* Fix constructing application with non-configurable prototype properties
* Fix `ECONNRESET` errors from `res.sendFile` usage
* Fix `req.host` when using "trust proxy" hops count
* Fix `req.protocol`/`req.secure` when using "trust proxy" hops count
* Fix wrong `code` on aborted connections from `res.sendFile`
* deps: merge-descriptors@1.0.0
4.12.0 / 2015-02-23
===================
* Fix `"trust proxy"` setting to inherit when app is mounted
* Generate `ETag`s for all request responses
- No longer restricted to only responses for `GET` and `HEAD` requests
* Use `content-type` to parse `Content-Type` headers
* deps: accepts@~1.2.4
- Fix preference sorting to be stable for long acceptable lists
- deps: mime-types@~2.0.9
- deps: negotiator@0.5.1
* deps: cookie-signature@1.0.6
* deps: send@0.12.1
- Always read the stat size from the file
- Fix mutating passed-in `options`
- deps: mime@1.3.4
* deps: serve-static@~1.9.1
- deps: send@0.12.1
* deps: type-is@~1.6.0
- fix argument reassignment
- fix false-positives in `hasBody` `Transfer-Encoding` check
- support wildcard for both type and subtype (`*/*`)
- deps: mime-types@~2.0.9
4.11.2 / 2015-02-01
===================
* Fix `res.redirect` double-calling `res.end` for `HEAD` requests
* deps: accepts@~1.2.3
- deps: mime-types@~2.0.8
* deps: proxy-addr@~1.0.6
- deps: ipaddr.js@0.1.8
* deps: type-is@~1.5.6
- deps: mime-types@~2.0.8
4.11.1 / 2015-01-20
===================
* deps: send@0.11.1
- Fix root path disclosure
* deps: serve-static@~1.8.1
- Fix redirect loop in Node.js 0.11.14
- Fix root path disclosure
- deps: send@0.11.1
4.11.0 / 2015-01-13
===================
* Add `res.append(field, val)` to append headers
* Deprecate leading `:` in `name` for `app.param(name, fn)`
* Deprecate `req.param()` -- use `req.params`, `req.body`, or `req.query` instead
* Deprecate `app.param(fn)`
* Fix `OPTIONS` responses to include the `HEAD` method properly
* Fix `res.sendFile` not always detecting aborted connection
* Match routes iteratively to prevent stack overflows
* deps: accepts@~1.2.2
- deps: mime-types@~2.0.7
- deps: negotiator@0.5.0
* deps: send@0.11.0
- deps: debug@~2.1.1
- deps: etag@~1.5.1
- deps: ms@0.7.0
- deps: on-finished@~2.2.0
* deps: serve-static@~1.8.0
- deps: send@0.11.0
4.10.8 / 2015-01-13
===================
* Fix crash from error within `OPTIONS` response handler
* deps: proxy-addr@~1.0.5
- deps: ipaddr.js@0.1.6
4.10.7 / 2015-01-04
===================
* Fix `Allow` header for `OPTIONS` to not contain duplicate methods
* Fix incorrect "Request aborted" for `res.sendFile` when `HEAD` or 304
* deps: debug@~2.1.1
* deps: finalhandler@0.3.3
- deps: debug@~2.1.1
- deps: on-finished@~2.2.0
* deps: methods@~1.1.1
* deps: on-finished@~2.2.0
* deps: serve-static@~1.7.2
- Fix potential open redirect when mounted at root
* deps: type-is@~1.5.5
- deps: mime-types@~2.0.7
4.10.6 / 2014-12-12
===================
* Fix exception in `req.fresh`/`req.stale` without response headers
4.10.5 / 2014-12-10
===================
* Fix `res.send` double-calling `res.end` for `HEAD` requests
* deps: accepts@~1.1.4
- deps: mime-types@~2.0.4
* deps: type-is@~1.5.4
- deps: mime-types@~2.0.4
4.10.4 / 2014-11-24
===================
* Fix `res.sendfile` logging standard write errors
4.10.3 / 2014-11-23
===================
* Fix `res.sendFile` logging standard write errors
* deps: etag@~1.5.1
* deps: proxy-addr@~1.0.4
- deps: ipaddr.js@0.1.5
* deps: qs@2.3.3
- Fix `arrayLimit` behavior
4.10.2 / 2014-11-09
===================
* Correctly invoke async router callback asynchronously
* deps: accepts@~1.1.3
- deps: mime-types@~2.0.3
* deps: type-is@~1.5.3
- deps: mime-types@~2.0.3
4.10.1 / 2014-10-28
===================
* Fix handling of URLs containing `://` in the path
* deps: qs@2.3.2
- Fix parsing of mixed objects and values
4.10.0 / 2014-10-23
===================
* Add support for `app.set('views', array)`
- Views are looked up in sequence in array of directories
* Fix `res.send(status)` to mention `res.sendStatus(status)`
* Fix handling of invalid empty URLs
* Use `content-disposition` module for `res.attachment`/`res.download`
- Sends standards-compliant `Content-Disposition` header
- Full Unicode support
* Use `path.resolve` in view lookup
* deps: debug@~2.1.0
- Implement `DEBUG_FD` env variable support
* deps: depd@~1.0.0
* deps: etag@~1.5.0
- Improve string performance
- Slightly improve speed for weak ETags over 1KB
* deps: finalhandler@0.3.2
- Terminate in progress response only on error
- Use `on-finished` to determine request status
- deps: debug@~2.1.0
- deps: on-finished@~2.1.1
* deps: on-finished@~2.1.1
- Fix handling of pipelined requests
* deps: qs@2.3.0
- Fix parsing of mixed implicit and explicit arrays
* deps: send@0.10.1
- deps: debug@~2.1.0
- deps: depd@~1.0.0
- deps: etag@~1.5.0
- deps: on-finished@~2.1.1
* deps: serve-static@~1.7.1
- deps: send@0.10.1
4.9.8 / 2014-10-17
==================
* Fix `res.redirect` body when redirect status specified
* deps: accepts@~1.1.2
- Fix error when media type has invalid parameter
- deps: negotiator@0.4.9
4.9.7 / 2014-10-10
==================
* Fix using same param name in array of paths
4.9.6 / 2014-10-08
==================
* deps: accepts@~1.1.1
- deps: mime-types@~2.0.2
- deps: negotiator@0.4.8
* deps: serve-static@~1.6.4
- Fix redirect loop when index file serving disabled
* deps: type-is@~1.5.2
- deps: mime-types@~2.0.2
4.9.5 / 2014-09-24
==================
* deps: etag@~1.4.0
* deps: proxy-addr@~1.0.3
- Use `forwarded` npm module
* deps: send@0.9.3
- deps: etag@~1.4.0
* deps: serve-static@~1.6.3
- deps: send@0.9.3
4.9.4 / 2014-09-19
==================
* deps: qs@2.2.4
- Fix issue with object keys starting with numbers truncated
4.9.3 / 2014-09-18
==================
* deps: proxy-addr@~1.0.2
- Fix a global leak when multiple subnets are trusted
- deps: ipaddr.js@0.1.3
4.9.2 / 2014-09-17
==================
* Fix regression for empty string `path` in `app.use`
* Fix `router.use` to accept array of middleware without path
* Improve error message for bad `app.use` arguments
4.9.1 / 2014-09-16
==================
* Fix `app.use` to accept array of middleware without path
* deps: depd@0.4.5
* deps: etag@~1.3.1
* deps: send@0.9.2
- deps: depd@0.4.5
- deps: etag@~1.3.1
- deps: range-parser@~1.0.2
* deps: serve-static@~1.6.2
- deps: send@0.9.2
4.9.0 / 2014-09-08
==================
* Add `res.sendStatus`
* Invoke callback for sendfile when client aborts
- Applies to `res.sendFile`, `res.sendfile`, and `res.download`
- `err` will be populated with request aborted error
* Support IP address host in `req.subdomains`
* Use `etag` to generate `ETag` headers
* deps: accepts@~1.1.0
- update `mime-types`
* deps: cookie-signature@1.0.5
* deps: debug@~2.0.0
* deps: finalhandler@0.2.0
- Set `X-Content-Type-Options: nosniff` header
- deps: debug@~2.0.0
* deps: fresh@0.2.4
* deps: media-typer@0.3.0
- Throw error when parameter format invalid on parse
* deps: qs@2.2.3
- Fix issue where first empty value in array is discarded
* deps: range-parser@~1.0.2
* deps: send@0.9.1
- Add `lastModified` option
- Use `etag` to generate `ETag` header
- deps: debug@~2.0.0
- deps: fresh@0.2.4
* deps: serve-static@~1.6.1
- Add `lastModified` option
- deps: send@0.9.1
* deps: type-is@~1.5.1
- fix `hasbody` to be true for `content-length: 0`
- deps: media-typer@0.3.0
- deps: mime-types@~2.0.1
* deps: vary@~1.0.0
- Accept valid `Vary` header string as `field`
4.8.8 / 2014-09-04
==================
* deps: send@0.8.5
- Fix a path traversal issue when using `root`
- Fix malicious path detection for empty string path
* deps: serve-static@~1.5.4
- deps: send@0.8.5
4.8.7 / 2014-08-29
==================
* deps: qs@2.2.2
- Remove unnecessary cloning
4.8.6 / 2014-08-27
==================
* deps: qs@2.2.0
- Array parsing fix
- Performance improvements
4.8.5 / 2014-08-18
==================
* deps: send@0.8.3
- deps: destroy@1.0.3
- deps: on-finished@2.1.0
* deps: serve-static@~1.5.3
- deps: send@0.8.3
4.8.4 / 2014-08-14
==================
* deps: qs@1.2.2
* deps: send@0.8.2
- Work around `fd` leak in Node.js 0.10 for `fs.ReadStream`
* deps: serve-static@~1.5.2
- deps: send@0.8.2
4.8.3 / 2014-08-10
==================
* deps: parseurl@~1.3.0
* deps: qs@1.2.1
* deps: serve-static@~1.5.1
- Fix parsing of weird `req.originalUrl` values
- deps: parseurl@~1.3.0
- deps: utils-merge@1.0.0
4.8.2 / 2014-08-07
==================
* deps: qs@1.2.0
- Fix parsing array of objects
4.8.1 / 2014-08-06
==================
* fix incorrect deprecation warnings on `res.download`
* deps: qs@1.1.0
- Accept urlencoded square brackets
- Accept empty values in implicit array notation
4.8.0 / 2014-08-05
==================
* add `res.sendFile`
- accepts a file system path instead of a URL
- requires an absolute path or `root` option specified
* deprecate `res.sendfile` -- use `res.sendFile` instead
* support mounted app as any argument to `app.use()`
* deps: qs@1.0.2
- Complete rewrite
- Limits array length to 20
- Limits object depth to 5
- Limits parameters to 1,000
* deps: send@0.8.1
- Add `extensions` option
* deps: serve-static@~1.5.0
- Add `extensions` option
- deps: send@0.8.1
4.7.4 / 2014-08-04
==================
* fix `res.sendfile` regression for serving directory index files
* deps: send@0.7.4
- Fix incorrect 403 on Windows and Node.js 0.11
- Fix serving index files without root dir
* deps: serve-static@~1.4.4
- deps: send@0.7.4
4.7.3 / 2014-08-04
==================
* deps: send@0.7.3
- Fix incorrect 403 on Windows and Node.js 0.11
* deps: serve-static@~1.4.3
- Fix incorrect 403 on Windows and Node.js 0.11
- deps: send@0.7.3
4.7.2 / 2014-07-27
==================
* deps: depd@0.4.4
- Work-around v8 generating empty stack traces
* deps: send@0.7.2
- deps: depd@0.4.4
* deps: serve-static@~1.4.2
4.7.1 / 2014-07-26
==================
* deps: depd@0.4.3
- Fix exception when global `Error.stackTraceLimit` is too low
* deps: send@0.7.1
- deps: depd@0.4.3
* deps: serve-static@~1.4.1
4.7.0 / 2014-07-25
==================
* fix `req.protocol` for proxy-direct connections
* configurable query parser with `app.set('query parser', parser)`
- `app.set('query parser', 'extended')` parse with "qs" module
- `app.set('query parser', 'simple')` parse with "querystring" core module
- `app.set('query parser', false)` disable query string parsing
- `app.set('query parser', true)` enable simple parsing
* deprecate `res.json(status, obj)` -- use `res.status(status).json(obj)` instead
* deprecate `res.jsonp(status, obj)` -- use `res.status(status).jsonp(obj)` instead
* deprecate `res.send(status, body)` -- use `res.status(status).send(body)` instead
* deps: debug@1.0.4
* deps: depd@0.4.2
- Add `TRACE_DEPRECATION` environment variable
- Remove non-standard grey color from color output
- Support `--no-deprecation` argument
- Support `--trace-deprecation` argument
* deps: finalhandler@0.1.0
- Respond after request fully read
- deps: debug@1.0.4
* deps: parseurl@~1.2.0
- Cache URLs based on original value
- Remove no-longer-needed URL mis-parse work-around
- Simplify the "fast-path" `RegExp`
* deps: send@0.7.0
- Add `dotfiles` option
- Cap `maxAge` value to 1 year
- deps: debug@1.0.4
- deps: depd@0.4.2
* deps: serve-static@~1.4.0
- deps: parseurl@~1.2.0
- deps: send@0.7.0
* perf: prevent multiple `Buffer` creation in `res.send`
4.6.1 / 2014-07-12
==================
* fix `subapp.mountpath` regression for `app.use(subapp)`
4.6.0 / 2014-07-11
==================
* accept multiple callbacks to `app.use()`
* add explicit "Rosetta Flash JSONP abuse" protection
- previous versions are not vulnerable; this is just explicit protection
* catch errors in multiple `req.param(name, fn)` handlers
* deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
* fix `res.send(status, num)` to send `num` as json (not error)
* remove unnecessary escaping when `res.jsonp` returns JSON response
* support non-string `path` in `app.use(path, fn)`
- supports array of paths
- supports `RegExp`
* router: fix optimization on router exit
* router: refactor location of `try` blocks
* router: speed up standard `app.use(fn)`
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
* deps: finalhandler@0.0.3
- deps: debug@1.0.3
* deps: methods@1.1.0
- add `CONNECT`
* deps: parseurl@~1.1.3
- faster parsing of href-only URLs
* deps: path-to-regexp@0.1.3
* deps: send@0.6.0
- deps: debug@1.0.3
* deps: serve-static@~1.3.2
- deps: parseurl@~1.1.3
- deps: send@0.6.0
* perf: fix arguments reassign deopt in some `res` methods
4.5.1 / 2014-07-06
==================
* fix routing regression when altering `req.method`
4.5.0 / 2014-07-04
==================
* add deprecation message to non-plural `req.accepts*`
* add deprecation message to `res.send(body, status)`
* add deprecation message to `res.vary()`
* add `headers` option to `res.sendfile`
- use to set headers on successful file transfer
* add `mergeParams` option to `Router`
- merges `req.params` from parent routes
* add `req.hostname` -- correct name for what `req.host` returns
* deprecate things with `depd` module
* deprecate `req.host` -- use `req.hostname` instead
* fix behavior when handling request without routes
* fix handling when `route.all` is only route
* invoke `router.param()` only when route matches
* restore `req.params` after invoking router
* use `finalhandler` for final response handling
* use `media-typer` to alter content-type charset
* deps: accepts@~1.0.7
* deps: send@0.5.0
- Accept string for `maxage` (converted by `ms`)
- Include link in default redirect response
* deps: serve-static@~1.3.0
- Accept string for `maxAge` (converted by `ms`)
- Add `setHeaders` option
- Include HTML link in redirect response
- deps: send@0.5.0
* deps: type-is@~1.3.2
4.4.5 / 2014-06-26
==================
* deps: cookie-signature@1.0.4
- fix for timing attacks
4.4.4 / 2014-06-20
==================
* fix `res.attachment` Unicode filenames in Safari
* fix "trim prefix" debug message in `express:router`
* deps: accepts@~1.0.5
* deps: buffer-crc32@0.2.3
4.4.3 / 2014-06-11
==================
* fix persistence of modified `req.params[name]` from `app.param()`
* deps: accepts@1.0.3
- deps: negotiator@0.4.6
* deps: debug@1.0.2
* deps: send@0.4.3
- Do not throw un-catchable error on file open race condition
- Use `escape-html` for HTML escaping
- deps: debug@1.0.2
- deps: finished@1.2.2
- deps: fresh@0.2.2
* deps: serve-static@1.2.3
- Do not throw un-catchable error on file open race condition
- deps: send@0.4.3
4.4.2 / 2014-06-09
==================
* fix catching errors from top-level handlers
* use `vary` module for `res.vary`
* deps: debug@1.0.1
* deps: proxy-addr@1.0.1
* deps: send@0.4.2
- fix "event emitter leak" warnings
- deps: debug@1.0.1
- deps: finished@1.2.1
* deps: serve-static@1.2.2
- fix "event emitter leak" warnings
- deps: send@0.4.2
* deps: type-is@1.2.1
4.4.1 / 2014-06-02
==================
* deps: methods@1.0.1
* deps: send@0.4.1
- Send `max-age` in `Cache-Control` in correct format
* deps: serve-static@1.2.1
- use `escape-html` for escaping
- deps: send@0.4.1
4.4.0 / 2014-05-30
==================
* custom etag control with `app.set('etag', val)`
- `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
- `app.set('etag', 'weak')` weak tag
- `app.set('etag', 'strong')` strong etag
- `app.set('etag', false)` turn off
- `app.set('etag', true)` standard etag
* mark `res.send` ETag as weak and reduce collisions
* update accepts to 1.0.2
- Fix interpretation when header not in request
* update send to 0.4.0
- Calculate ETag with md5 for reduced collisions
- Ignore stream errors after request ends
- deps: debug@0.8.1
* update serve-static to 1.2.0
- Calculate ETag with md5 for reduced collisions
- Ignore stream errors after request ends
- deps: send@0.4.0
4.3.2 / 2014-05-28
==================
* fix handling of errors from `router.param()` callbacks
4.3.1 / 2014-05-23
==================
* revert "fix behavior of multiple `app.VERB` for the same path"
- this caused a regression in the order of route execution
4.3.0 / 2014-05-21
==================
* add `req.baseUrl` to access the path stripped from `req.url` in routes
* fix behavior of multiple `app.VERB` for the same path
* fix issue routing requests among sub routers
* invoke `router.param()` only when necessary instead of every match
* proper proxy trust with `app.set('trust proxy', trust)`
- `app.set('trust proxy', 1)` trust first hop
- `app.set('trust proxy', 'loopback')` trust loopback addresses
- `app.set('trust proxy', '10.0.0.1')` trust single IP
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
- `app.set('trust proxy', false)` turn off
- `app.set('trust proxy', true)` trust everything
* set proper `charset` in `Content-Type` for `res.send`
* update type-is to 1.2.0
- support suffix matching
4.2.0 / 2014-05-11
==================
* deprecate `app.del()` -- use `app.delete()` instead
* deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
- the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
* deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
- the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
* fix `req.next` when inside router instance
* include `ETag` header in `HEAD` requests
* keep previous `Content-Type` for `res.jsonp`
* support PURGE method
- add `app.purge`
- add `router.purge`
- include PURGE in `app.all`
* update debug to 0.8.0
- add `enable()` method
- change from stderr to stdout
* update methods to 1.0.0
- add PURGE
4.1.2 / 2014-05-08
==================
* fix `req.host` for IPv6 literals
* fix `res.jsonp` error if callback param is object
4.1.1 / 2014-04-27
==================
* fix package.json to reflect supported node version
4.1.0 / 2014-04-24
==================
* pass options from `res.sendfile` to `send`
* preserve casing of headers in `res.header` and `res.set`
* support unicode file names in `res.attachment` and `res.download`
* update accepts to 1.0.1
- deps: negotiator@0.4.0
* update cookie to 0.1.2
- Fix for maxAge == 0
- made compat with expires field
* update send to 0.3.0
- Accept API options in options object
- Coerce option types
- Control whether to generate etags
- Default directory access to 403 when index disabled
- Fix sending files with dots without root set
- Include file path in etag
- Make "Can't set headers after they are sent." catchable
- Send full entity-body for multi range requests
- Set etags to "weak"
- Support "If-Range" header
- Support multiple index paths
- deps: mime@1.2.11
* update serve-static to 1.1.0
- Accept options directly to `send` module
- Resolve relative paths at middleware setup
- Use parseurl to parse the URL from request
- deps: send@0.3.0
* update type-is to 1.1.0
- add non-array values support
- add `multipart` as a shorthand
4.0.0 / 2014-04-09
==================
* remove:
- node 0.8 support
- connect and connect's patches except for charset handling
- express(1) - moved to [express-generator](https://github.com/expressjs/generator)
- `express.createServer()` - it has been deprecated for a long time. Use `express()`
- `app.configure` - use logic in your own app code
- `app.router` - is removed
- `req.auth` - use `basic-auth` instead
- `req.accepted*` - use `req.accepts*()` instead
- `res.location` - relative URL resolution is removed
- `res.charset` - include the charset in the content type when using `res.set()`
- all bundled middleware except `static`
* change:
- `app.route` -> `app.mountpath` when mounting an express app in another express app
- `json spaces` no longer enabled by default in development
- `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings`
- `req.params` is now an object instead of an array
- `res.locals` is no longer a function. It is a plain js object. Treat it as such.
- `res.headerSent` -> `res.headersSent` to match node.js ServerResponse object
* refactor:
- `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
- `req.is` with [type-is](https://github.com/expressjs/type-is)
- [path-to-regexp](https://github.com/component/path-to-regexp)
* add:
- `app.router()` - returns the app Router instance
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
- Router & Route - public API
3.21.2 / 2015-07-31
===================
@ -391,6 +1313,7 @@
3.17.0 / 2014-09-08
===================
* Support `X-Forwarded-Host` in `req.subdomains`
* Support IP address host in `req.subdomains`
* deps: connect@2.26.0
- deps: body-parser@~1.8.1
@ -1913,7 +2836,7 @@ Shaw]
* Added "encoding" option to Request#render(). Closes #299
* Added "dump exceptions" setting, which is enabled by default.
* Added simple ejs template engine support
* Added error reponse support for text/plain, application/json. Closes #297
* Added error response support for text/plain, application/json. Closes #297
* Added callback function param to Request#error()
* Added Request#sendHead()
* Added Request#stream()
@ -2127,7 +3050,7 @@ Shaw]
* Updated sample chat app to show messages on load
* Updated libxmljs parseString -> parseHtmlString
* Fixed `make init` to work with older versions of git
* Fixed specs can now run independant specs for those who cant build deps. Closes #127
* Fixed specs can now run independent specs for those who cant build deps. Closes #127
* Fixed issues introduced by the node url module changes. Closes 126.
* Fixed two assertions failing due to Collection#keys() returning strings
* Fixed faulty Collection#toArray() spec due to keys() returning strings

6
node_modules/express/LICENSE generated vendored
View File

@ -1,7 +1,7 @@
(The MIT License)
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
@ -21,4 +21,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

183
node_modules/express/Readme.md generated vendored
View File

@ -1,55 +1,79 @@
[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/)
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![NPM version](https://img.shields.io/npm/v/express.svg)](https://www.npmjs.org/package/express)
[![Build Status](https://img.shields.io/travis/strongloop/express/3.x.svg)](https://travis-ci.org/strongloop/express)
[![Coverage Status](https://img.shields.io/coveralls/strongloop/express/3.x.svg)](https://coveralls.io/r/strongloop/express)
[![Gratipay](https://img.shields.io/gratipay/dougwilson.svg)](https://gratipay.com/dougwilson/)
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Linux Build][travis-image]][travis-url]
[![Windows Build][appveyor-image]][appveyor-url]
[![Test Coverage][coveralls-image]][coveralls-url]
```js
var express = require('express');
var app = express();
var express = require('express')
var app = express()
app.get('/', function(req, res){
res.send('Hello World');
});
app.get('/', function (req, res) {
res.send('Hello World')
})
app.listen(3000);
app.listen(3000)
```
## Installation
$ npm install -g express
## Quick Start
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
Create the app:
$ npm install -g express
$ express /tmp/foo && cd /tmp/foo
Install dependencies:
$ npm install
Start the server:
$ node app
```bash
$ npm install express
```
## Features
* Built on [Connect](http://github.com/senchalabs/connect)
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Focus on high performance
* Environment based configuration
* Executable for generating applications quickly
* High test coverage
## Docs & Community
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
* [Русскоязычная документация](http://jsman.ru/express/)
###Security Issues
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).
## Quick Start
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
```bash
$ npm install -g express-generator@4
```
Create the app:
```bash
$ express /tmp/foo && cd /tmp/foo
```
Install dependencies:
```bash
$ npm install
```
Start the server:
```bash
$ npm start
```
## Philosophy
@ -57,75 +81,58 @@ app.listen(3000);
it a great solution for single page applications, web sites, hybrids, or public
HTTP APIs.
Built on Connect, you can use _only_ what you need, and nothing more. Applications
can be as big or as small as you like, even a single file. Express does
not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js),
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
you can quickly craft your perfect framework.
## More Information
## Examples
* [Website and Documentation](http://expressjs.com/) stored at [strongloop/expressjs.com](https://github.com/strongloop/expressjs.com)
* Join #express on freenode
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
* Visit the [Wiki](http://github.com/strongloop/express/wiki)
* [Русскоязычная документация](http://jsman.ru/express/)
* Run express examples [online](https://runnable.com/express)
To view the examples, clone the Express repo and install the dependencies:
## Viewing Examples
```bash
$ git clone git://github.com/expressjs/express.git --depth 1
$ cd express
$ npm install
```
Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:
Then run whichever example you want:
$ git clone git://github.com/strongloop/express.git --depth 1
$ cd express
$ npm install
```bash
$ node examples/content-negotiation
```
Then run whichever tests you want:
## Tests
$ node examples/content-negotiation
To run the test suite, first install the dependencies, then run `npm test`:
You can also view live examples here:
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
## Running Tests
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
$ npm install
Then run the tests:
```sh
```bash
$ npm install
$ npm test
```
## Contributors
## People
https://github.com/strongloop/express/graphs/contributors
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
## License
(The MIT License)
[MIT](LICENSE)
Copyright (c) 2009-2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[npm-image]: https://img.shields.io/npm/v/express.svg
[npm-url]: https://npmjs.org/package/express
[downloads-image]: https://img.shields.io/npm/dm/express.svg
[downloads-url]: https://npmjs.org/package/express
[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
[travis-url]: https://travis-ci.org/expressjs/express
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/

9
node_modules/express/index.js generated vendored
View File

@ -1,2 +1,11 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
module.exports = require('./lib/express');

View File

@ -6,23 +6,29 @@
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @api private
* @private
*/
var connect = require('connect')
, Router = require('./router')
, methods = require('methods')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, locals = require('./utils').locals
, compileETag = require('./utils').compileETag
, compileTrust = require('./utils').compileTrust
, View = require('./view')
, http = require('http');
var finalhandler = require('finalhandler');
var Router = require('./router');
var methods = require('methods');
var middleware = require('./middleware/init');
var query = require('./middleware/query');
var debug = require('debug')('express:application');
var View = require('./view');
var http = require('http');
var compileETag = require('./utils').compileETag;
var compileQueryParser = require('./utils').compileQueryParser;
var compileTrust = require('./utils').compileTrust;
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var merge = require('utils-merge');
var resolve = require('path').resolve;
var slice = Array.prototype.slice;
/**
* Application prototype.
@ -32,7 +38,7 @@ var app = exports = module.exports = {};
/**
* Variable for trust proxy inheritance back-compat
* @api private
* @private
*/
var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
@ -44,28 +50,30 @@ var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
* - setup default middleware
* - setup route reflection methods
*
* @api private
* @private
*/
app.init = function(){
app.init = function init() {
this.cache = {};
this.settings = {};
this.engines = {};
this.settings = {};
this.defaultConfiguration();
};
/**
* Initialize application configuration.
*
* @api private
* @private
*/
app.defaultConfiguration = function(){
app.defaultConfiguration = function defaultConfiguration() {
var env = process.env.NODE_ENV || 'development';
// default settings
this.enable('x-powered-by');
this.set('etag', 'weak');
var env = process.env.NODE_ENV || 'development';
this.set('env', env);
this.set('query parser', 'extended');
this.set('subdomain offset', 2);
this.set('trust proxy', false);
@ -77,10 +85,6 @@ app.defaultConfiguration = function(){
debug('booting in %s mode', env);
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
this.on('mount', function onmount(parent) {
// inherit trust proxy
if (this.settings[trustProxyDefaultSymbol] === true
@ -96,79 +100,161 @@ app.defaultConfiguration = function(){
this.settings.__proto__ = parent.settings;
});
// router
this._router = new Router(this);
this.routes = this._router.map;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});
// setup locals
this.locals = locals(this);
this.locals = Object.create(null);
// top-most app is mounted at /
this.mountpath = '/';
// default locals
this.locals.settings = this.settings;
// default configuration
this.set('view', View);
this.set('views', process.cwd() + '/views');
this.set('views', resolve('views'));
this.set('jsonp callback name', 'callback');
if (env === 'development') {
this.set('json spaces', 2);
}
if (env === 'production') {
this.enable('view cache');
}
Object.defineProperty(this, 'router', {
get: function() {
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
}
});
};
/**
* Proxy `connect#use()` to apply settings to
* mounted applications.
* lazily adds the base router if it has not yet been added.
*
* @param {String|Function|Server} route
* @param {Function|Server} fn
* @return {app} for chaining
* @api public
* We cannot add the base router in the defaultConfiguration because
* it reads app settings which might be set after that has run.
*
* @private
*/
app.lazyrouter = function lazyrouter() {
if (!this._router) {
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
});
this._router.use(query(this.get('query parser fn')));
this._router.use(middleware.init(this));
}
};
/**
* Dispatch a req, res pair into the application. Starts pipeline processing.
*
* If no callback is provided, then default error handlers will respond
* in the event of an error bubbling through the stack.
*
* @private
*/
app.use = function(route, fn){
var app;
app.handle = function handle(req, res, callback) {
var router = this._router;
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// final handler
var done = callback || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror.bind(this)
});
// express app
if (fn.handle && fn.set) app = fn;
// no routes
if (!router) {
debug('no routes defined on app');
done();
return;
}
// restore .app property on req and res
if (app) {
app.route = route;
fn = function(req, res, next) {
router.handle(req, res, done);
};
/**
* Proxy `Router#use()` to add middleware to the app router.
* See Router#use() documentation for details.
*
* If the _fn_ parameter is an express app, then it will be
* mounted at the _route_ specified.
*
* @public
*/
app.use = function use(fn) {
var offset = 0;
var path = '/';
// default path to '/'
// disambiguate app.use([fn])
if (typeof fn !== 'function') {
var arg = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
}
var fns = flatten(slice.call(arguments, offset));
if (fns.length === 0) {
throw new TypeError('app.use() requires middleware functions');
}
// setup router
this.lazyrouter();
var router = this._router;
fns.forEach(function (fn) {
// non-express app
if (!fn || !fn.handle || !fn.set) {
return router.use(path, fn);
}
debug('.use app under %s', path);
fn.mountpath = path;
fn.parent = this;
// restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
});
connect.proto.use.call(this, route, fn);
// mounted an app
if (app) {
app.parent = this;
app.emit('mount', this);
}
// mounted an app
fn.emit('mount', this);
}, this);
return this;
};
/**
* Proxy to the app `Router#route()`
* Returns a new `Route` instance for the _path_.
*
* Routes are isolated middleware stacks for specific paths.
* See the Route api docs for details.
*
* @public
*/
app.route = function route(path) {
this.lazyrouter();
return this._router.route(path);
};
/**
* Register the given template engine callback `fn`
* as `ext`.
@ -192,7 +278,7 @@ app.use = function(route, fn){
* so if you're using ".ejs" extensions you dont need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
* [Consolidate.js](https://github.com/tj/consolidate.js)
* library was created to map all of node's popular template
* engines to follow this convention, thus allowing them to
* work seamlessly within Express.
@ -200,70 +286,50 @@ app.use = function(route, fn){
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
app.engine = function(ext, fn){
if ('function' != typeof fn) throw new Error('callback function required');
if ('.' != ext[0]) ext = '.' + ext;
this.engines[ext] = fn;
app.engine = function engine(ext, fn) {
if (typeof fn !== 'function') {
throw new Error('callback function required');
}
// get file extension
var extension = ext[0] !== '.'
? '.' + ext
: ext;
// store engine
this.engines[extension] = fn;
return this;
};
/**
* Map the given param placeholder `name`(s) to the given callback(s).
* Proxy to `Router#param()` with one added api feature. The _name_ parameter
* can be an array of names.
*
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
* See the Router#param() docs for more details.
*
* @param {String|Array} name
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
app.param = function(name, fn){
var self = this
, fns = [].slice.call(arguments, 1);
app.param = function param(name, fn) {
this.lazyrouter();
// array
if (Array.isArray(name)) {
name.forEach(function(name){
fns.forEach(function(fn){
self.param(name, fn);
});
});
// param logic
} else if ('function' == typeof name) {
this._router.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
fns.forEach(function(fn){
self._router.param(name, fn);
});
for (var i = 0; i < name.length; i++) {
this.param(name[i], fn);
}
return this;
}
this._router.param(name, fn);
return this;
};
@ -279,26 +345,29 @@ app.param = function(name, fn){
* @param {String} setting
* @param {*} [val]
* @return {Server} for chaining
* @api public
* @public
*/
app.set = function(setting, val){
app.set = function set(setting, val) {
if (arguments.length === 1) {
// app.get(setting)
return this.settings[setting];
}
debug('set "%s" to %o', setting, val);
// set value
this.settings[setting] = val;
// trigger matched settings
switch (setting) {
case 'etag':
debug('compile etag %s', val);
this.set('etag fn', compileETag(val));
break;
case 'query parser':
this.set('query parser fn', compileQueryParser(val));
break;
case 'trust proxy':
debug('compile trust proxy %s', val);
this.set('trust proxy fn', compileTrust(val));
// trust proxy inherit back-compat
@ -324,12 +393,12 @@ app.set = function(setting, val){
* return value would be "/blog/admin".
*
* @return {String}
* @api private
* @private
*/
app.path = function(){
app.path = function path() {
return this.parent
? this.parent.path() + this.route
? this.parent.path() + this.mountpath
: '';
};
@ -345,11 +414,11 @@ app.path = function(){
*
* @param {String} setting
* @return {Boolean}
* @api public
* @public
*/
app.enabled = function(setting){
return !!this.set(setting);
app.enabled = function enabled(setting) {
return Boolean(this.set(setting));
};
/**
@ -364,10 +433,10 @@ app.enabled = function(setting){
*
* @param {String} setting
* @return {Boolean}
* @api public
* @public
*/
app.disabled = function(setting){
app.disabled = function disabled(setting) {
return !this.set(setting);
};
@ -376,10 +445,10 @@ app.disabled = function(setting){
*
* @param {String} setting
* @return {app} for chaining
* @api public
* @public
*/
app.enable = function(setting){
app.enable = function enable(setting) {
return this.set(setting, true);
};
@ -388,83 +457,28 @@ app.enable = function(setting){
*
* @param {String} setting
* @return {app} for chaining
* @api public
* @public
*/
app.disable = function(setting){
app.disable = function disable(setting) {
return this.set(setting, false);
};
/**
* Configure callback for zero or more envs,
* when no `env` is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* Note:
*
* These callbacks are invoked immediately, and
* are effectively sugar for the following:
*
* var env = process.env.NODE_ENV || 'development';
*
* switch (env) {
* case 'development':
* ...
* break;
* case 'stage':
* ...
* break;
* case 'production':
* ...
* break;
* }
*
* @param {String} env...
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = [].slice.call(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
app.configure = deprecate.function(app.configure,
'app.configure: Check app.get(\'env\') in an if statement');
/**
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
if (method === 'get' && arguments.length === 1) {
// app.get(setting)
return this.set(path);
}
// if no router attached yet, attach the router
if (!this._usedRouter) this.use(this.router);
this.lazyrouter();
// setup route
this._router[method].apply(this._router, arguments);
var route = this._router.route(path);
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
@ -476,14 +490,19 @@ methods.forEach(function(method){
* @param {String} path
* @param {Function} ...
* @return {app} for chaining
* @api public
* @public
*/
app.all = function(path){
var args = arguments;
methods.forEach(function(method){
app[method].apply(this, args);
}, this);
app.all = function all(path) {
this.lazyrouter();
var route = this._router.route(path);
var args = slice.call(arguments, 1);
for (var i = 0; i < methods.length; i++) {
route[methods[i]].apply(route, args);
}
return this;
};
@ -503,65 +522,73 @@ app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
* })
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} fn
* @api public
* @param {Object|Function} options or fn
* @param {Function} callback
* @public
*/
app.render = function(name, options, fn){
var opts = {}
, cache = this.cache
, engines = this.engines
, view;
app.render = function render(name, options, callback) {
var cache = this.cache;
var done = callback;
var engines = this.engines;
var opts = options;
var renderOptions = {};
var view;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge app.locals
merge(opts, this.locals);
merge(renderOptions, this.locals);
// merge options._locals
if (options._locals) {
merge(opts, options._locals);
if (opts._locals) {
merge(renderOptions, opts._locals);
}
// merge options
merge(opts, options);
merge(renderOptions, opts);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
? this.enabled('view cache')
: opts.cache;
if (renderOptions.cache == null) {
renderOptions.cache = this.enabled('view cache');
}
// primed cache
if (opts.cache) view = cache[name];
if (renderOptions.cache) {
view = cache[name];
}
// view
if (!view) {
view = new (this.get('view'))(name, {
var View = this.get('view');
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
var dirs = Array.isArray(view.root) && view.root.length > 1
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
: 'directory "' + view.root + '"'
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
err.view = view;
return fn(err);
return done(err);
}
// prime the cache
if (opts.cache) cache[name] = view;
if (renderOptions.cache) {
cache[name] = view;
}
}
// render
try {
view.render(opts, fn);
} catch (err) {
fn(err);
}
tryRender(view, renderOptions, done);
};
/**
@ -582,10 +609,35 @@ app.render = function(name, options, fn){
* https.createServer({ ... }, app).listen(443);
*
* @return {http.Server}
* @api public
* @public
*/
app.listen = function(){
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Log error using console.error.
*
* @param {Error} err
* @private
*/
function logerror(err) {
/* istanbul ignore next */
if (this.get('env') !== 'test') console.error(err.stack || err.toString());
}
/**
* Try rendering a view.
* @private
*/
function tryRender(view, options, callback) {
try {
view.render(options, callback);
} catch (err) {
callback(err);
}
}

99
node_modules/express/lib/express.js generated vendored
View File

@ -1,16 +1,24 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
*/
var deprecate = require('depd')('express');
var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');
var merge = require('utils-merge');
var connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response');
var proto = require('./application');
var Route = require('./router/route');
var Router = require('./router');
var req = require('./request');
var res = require('./response');
/**
* Expose `createApplication()`.
@ -18,12 +26,6 @@ var connect = require('connect')
exports = module.exports = createApplication;
/**
* Expose mime.
*/
exports.mime = connect.mime;
/**
* Create an express application.
*
@ -32,35 +34,19 @@ exports.mime = connect.mime;
*/
function createApplication() {
var app = connect();
merge(app, proto);
var app = function(req, res, next) {
app.handle(req, res, next);
};
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
}
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
mixin(exports, connect.middleware);
/**
* Deprecated createServer().
*/
exports.createServer = deprecate.function(createApplication,
'createServer() is deprecated\n' +
'express applications no longer inherit from http.Server\n' +
'please use:\n' +
'\n' +
' var express = require("express");\n' +
' var app = express();\n' +
'\n'
);
/**
* Expose the prototypes.
*/
@ -76,7 +62,42 @@ exports.response = res;
exports.Route = Route;
exports.Router = Router;
// Error handler title
/**
* Expose middleware
*/
exports.errorHandler.title = 'Express';
exports.query = require('./middleware/query');
exports.static = require('serve-static');
/**
* Replace removed middleware with an appropriate error message.
*/
[
'json',
'urlencoded',
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache',
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});

349
node_modules/express/lib/request.js generated vendored
View File

@ -1,19 +1,27 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var auth = require('basic-auth');
var accepts = require('accepts');
var deprecate = require('depd')('express');
var http = require('http')
, utils = require('./utils')
, connect = require('connect')
, fresh = require('fresh')
, parseRange = require('range-parser')
, parse = require('parseurl')
, proxyaddr = require('proxy-addr')
, mime = connect.mime;
var isIP = require('net').isIP;
var typeis = require('type-is');
var http = require('http');
var fresh = require('fresh');
var parseRange = require('range-parser');
var parse = require('parseurl');
var proxyaddr = require('proxy-addr');
/**
* Request prototype.
@ -44,32 +52,36 @@ var req = exports = module.exports = {
*
* @param {String} name
* @return {String}
* @api public
* @public
*/
req.get =
req.header = function(name){
switch (name = name.toLowerCase()) {
req.header = function header(name) {
var lc = name.toLowerCase();
switch (lc) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer;
default:
return this.headers[name];
return this.headers[lc];
}
};
/**
* To do: update docs.
*
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json", a comma-delimted list such as "json, html, text/plain",
* The `type` value may be a single MIME type string
* such as "application/json", an extension name
* such as "json", a comma-delimited list such as "json, html, text/plain",
* an argument list such as `"json", "html", "text/plain"`,
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
* or array is given, the _best_ match, if any is returned.
*
* Examples:
*
@ -99,59 +111,65 @@ req.header = function(name){
* // => "json"
*
* @param {String|Array} type(s)
* @return {String}
* @api public
* @return {String|Array|Boolean}
* @public
*/
req.accepts = function(type){
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
return utils.accepts(args, this.get('Accept'));
req.accepts = function(){
var accept = accepts(this);
return accept.types.apply(accept, arguments);
};
/**
* Check if the given `encoding` is accepted.
* Check if the given `encoding`s are accepted.
*
* @param {String} encoding
* @return {Boolean}
* @api public
* @param {String} ...encoding
* @return {String|Array}
* @public
*/
req.acceptsEncoding = function(encoding){
return !! ~this.acceptedEncodings.indexOf(encoding);
req.acceptsEncodings = function(){
var accept = accepts(this);
return accept.encodings.apply(accept, arguments);
};
req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
'req.acceptsEncoding: Use acceptsEncodings instead');
/**
* Check if the given `charset` is acceptable,
* Check if the given `charset`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} charset
* @return {Boolean}
* @api public
* @param {String} ...charset
* @return {String|Array}
* @public
*/
req.acceptsCharset = function(charset){
var accepted = this.acceptedCharsets;
return accepted.length
? !! ~accepted.indexOf(charset)
: true;
req.acceptsCharsets = function(){
var accept = accepts(this);
return accept.charsets.apply(accept, arguments);
};
req.acceptsCharset = deprecate.function(req.acceptsCharsets,
'req.acceptsCharset: Use acceptsCharsets instead');
/**
* Check if the given `lang` is acceptable,
* Check if the given `lang`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} lang
* @return {Boolean}
* @api public
* @param {String} ...lang
* @return {String|Array}
* @public
*/
req.acceptsLanguage = function(lang){
var accepted = this.acceptedLanguages;
return accepted.length
? !! ~accepted.indexOf(lang)
: true;
req.acceptsLanguages = function(){
var accept = accepts(this);
return accept.languages.apply(accept, arguments);
};
req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
'req.acceptsLanguage: Use acceptsLanguages instead');
/**
* Parse Range header field,
* capping to the given `size`.
@ -169,7 +187,7 @@ req.acceptsLanguage = function(lang){
*
* @param {Number} size
* @return {Array}
* @api public
* @public
*/
req.range = function(size){
@ -178,98 +196,6 @@ req.range = function(size){
return parseRange(size, range);
};
/**
* Return an array of encodings.
*
* Examples:
*
* ['gzip', 'deflate']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedEncodings', function(){
var accept = this.get('Accept-Encoding');
return accept
? accept.trim().split(/ *, */)
: [];
});
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.
*
* Examples:
*
* [ { value: 'application/json',
* quality: 1,
* type: 'application',
* subtype: 'json' },
* { value: 'text/html',
* quality: 0.5,
* type: 'text',
* subtype: 'html' } ]
*
* @return {Array}
* @api public
*/
req.__defineGetter__('accepted', function(){
var accept = this.get('Accept');
return accept
? utils.parseAccept(accept)
: [];
});
/**
* Return an array of Accepted languages
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Language: en;q=.5, en-us
* ['en-us', 'en']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedLanguages', function(){
var accept = this.get('Accept-Language');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return an array of Accepted charsets
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
* ['unicode-1-1', 'iso-8859-5']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedCharsets', function(){
var accept = this.get('Accept-Charset');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return the value of param `name` when present or `defaultValue`.
*
@ -279,21 +205,28 @@ req.__defineGetter__('acceptedCharsets', function(){
*
* To utilize request bodies, `req.body`
* should be an object. This can be done by using
* the `connect.bodyParser()` middleware.
* the `bodyParser()` middleware.
*
* @param {String} name
* @param {Mixed} [defaultValue]
* @return {String}
* @api public
* @public
*/
req.param = function(name, defaultValue){
req.param = function param(name, defaultValue) {
var params = this.params || {};
var body = this.body || {};
var query = this.query || {};
var args = arguments.length === 1
? 'name'
: 'name, default';
deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead');
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
if (null != body[name]) return body[name];
if (null != query[name]) return query[name];
return defaultValue;
};
@ -318,24 +251,23 @@ req.param = function(name, defaultValue){
* req.is('html');
* // => false
*
* @param {String} type
* @return {Boolean}
* @api public
* @param {String|Array} types...
* @return {String|false|null}
* @public
*/
req.is = function(type){
var ct = this.get('Content-Type');
if (!ct) return false;
ct = ct.split(';')[0];
if (!~type.indexOf('/')) type = mime.lookup(type);
if (~type.indexOf('*')) {
type = type.split('/');
ct = ct.split('/');
if ('*' == type[0] && type[1] == ct[1]) return true;
if ('*' == type[1] && type[0] == ct[0]) return true;
return false;
req.is = function is(types) {
var arr = types;
// support flattened arguments
if (!Array.isArray(types)) {
arr = new Array(arguments.length);
for (var i = 0; i < arr.length; i++) {
arr[i] = arguments[i];
}
}
return !! ~ct.indexOf(type);
return typeis(this, arr);
};
/**
@ -349,10 +281,10 @@ req.is = function(type){
* supplies https for you this may be enabled.
*
* @return {String}
* @api public
* @public
*/
req.__defineGetter__('protocol', function(){
defineGetter(req, 'protocol', function protocol(){
var proto = this.connection.encrypted
? 'https'
: 'http';
@ -374,11 +306,11 @@ req.__defineGetter__('protocol', function(){
* req.protocol == 'https'
*
* @return {Boolean}
* @api public
* @public
*/
req.__defineGetter__('secure', function(){
return 'https' == this.protocol;
defineGetter(req, 'secure', function secure(){
return this.protocol === 'https';
});
/**
@ -388,10 +320,10 @@ req.__defineGetter__('secure', function(){
* "trust proxy" is set.
*
* @return {String}
* @api public
* @public
*/
req.__defineGetter__('ip', function(){
defineGetter(req, 'ip', function ip(){
var trust = this.app.get('trust proxy fn');
return proxyaddr(this, trust);
});
@ -405,38 +337,15 @@ req.__defineGetter__('ip', function(){
* "proxy2" were trusted.
*
* @return {Array}
* @api public
* @public
*/
req.__defineGetter__('ips', function(){
defineGetter(req, 'ips', function ips() {
var trust = this.app.get('trust proxy fn');
var addrs = proxyaddr.all(this, trust);
return addrs.slice(1).reverse();
});
/**
* Return basic auth credentials.
*
* Examples:
*
* // http://tobi:hello@example.com
* req.auth
* // => { username: 'tobi', password: 'hello' }
*
* @return {Object} or undefined
* @api public
*/
req.__defineGetter__('auth', function(){
deprecate('req.auth: Use basic-auth npm module instead');
// credentials
var creds = auth(this);
if (!creds) return;
return { username: creds.name, password: creds.pass };
});
/**
* Return subdomains as an array.
*
@ -449,18 +358,18 @@ req.__defineGetter__('auth', function(){
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
*
* @return {Array}
* @api public
* @public
*/
req.__defineGetter__('subdomains', function(){
var host = this.host;
defineGetter(req, 'subdomains', function subdomains() {
var hostname = this.hostname;
if (!host) return [];
if (!hostname) return [];
var offset = this.app.get('subdomain offset');
var subdomains = !isIP(host)
? host.split('.').reverse()
: [host];
var subdomains = !isIP(hostname)
? hostname.split('.').reverse()
: [hostname];
return subdomains.slice(offset);
});
@ -469,25 +378,25 @@ req.__defineGetter__('subdomains', function(){
* Short-hand for `url.parse(req.url).pathname`.
*
* @return {String}
* @api public
* @public
*/
req.__defineGetter__('path', function(){
defineGetter(req, 'path', function path() {
return parse(this).pathname;
});
/**
* Parse the "Host" header field hostname.
* Parse the "Host" header field to a hostname.
*
* When the "trust proxy" setting trusts the socket
* address, the "X-Forwarded-Host" header field will
* be trusted.
*
* @return {String}
* @api public
* @public
*/
req.__defineGetter__('host', function(){
defineGetter(req, 'hostname', function hostname(){
var trust = this.app.get('trust proxy fn');
var host = this.get('X-Forwarded-Host');
@ -503,21 +412,27 @@ req.__defineGetter__('host', function(){
: 0;
var index = host.indexOf(':', offset);
return ~index
return index !== -1
? host.substring(0, index)
: host;
});
// TODO: change req.host to return host in next major
defineGetter(req, 'host', deprecate.function(function host(){
return this.hostname;
}, 'req.host: Use req.hostname instead'));
/**
* Check if the request is fresh, aka
* Last-Modified and/or the ETag
* still match.
*
* @return {Boolean}
* @api public
* @public
*/
req.__defineGetter__('fresh', function(){
defineGetter(req, 'fresh', function(){
var method = this.method;
var s = this.res.statusCode;
@ -538,10 +453,10 @@ req.__defineGetter__('fresh', function(){
* resource has changed.
*
* @return {Boolean}
* @api public
* @public
*/
req.__defineGetter__('stale', function(){
defineGetter(req, 'stale', function stale(){
return !this.fresh;
});
@ -549,10 +464,26 @@ req.__defineGetter__('stale', function(){
* Check if the request was an _XMLHttpRequest_.
*
* @return {Boolean}
* @api public
* @public
*/
req.__defineGetter__('xhr', function(){
defineGetter(req, 'xhr', function xhr(){
var val = this.get('X-Requested-With') || '';
return 'xmlhttprequest' == val.toLowerCase();
return val.toLowerCase() === 'xmlhttprequest';
});
/**
* Helper function for creating a getter on an object.
*
* @param {Object} obj
* @param {String} name
* @param {Function} getter
* @private
*/
function defineGetter(obj, name, getter) {
Object.defineProperty(obj, name, {
configurable: true,
enumerable: true,
get: getter
});
};

743
node_modules/express/lib/response.js generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +1,115 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var Route = require('./route');
var utils = require('../utils');
var Layer = require('./layer');
var methods = require('methods');
var mixin = require('utils-merge');
var debug = require('debug')('express:router');
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var parseUrl = require('parseurl');
/**
* Expose `Router` constructor.
* Module variables.
* @private
*/
exports = module.exports = Router;
var objectRegExp = /^\[object (\S+)\]$/;
var slice = Array.prototype.slice;
var toString = Object.prototype.toString;
/**
* Initialize a new `Router` with the given `options`.
*
* @param {Object} options
* @api private
* @return {Router} which is an callable function
* @public
*/
function Router(options) {
options = options || {};
var self = this;
this.map = {};
this.params = {};
this._params = [];
this.caseSensitive = options.caseSensitive;
this.strict = options.strict;
this.middleware = function router(req, res, next){
self._dispatch(req, res, next);
};
}
var proto = module.exports = function(options) {
var opts = options || {};
function router(req, res, next) {
router.handle(req, res, next);
}
// mixin Router class functions
router.__proto__ = proto;
router.params = {};
router._params = [];
router.caseSensitive = opts.caseSensitive;
router.mergeParams = opts.mergeParams;
router.strict = opts.strict;
router.stack = [];
return router;
};
/**
* Register a param callback `fn` for the given `name`.
* Map the given param placeholder `name`(s) to the given callback.
*
* @param {String|Function} name
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* Just like in middleware, you must either respond to the request or call next
* to avoid stalling the request.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* return next(err);
* } else if (!user) {
* return next(new Error('failed to load user'));
* }
* req.user = user;
* next();
* });
* });
*
* @param {String} name
* @param {Function} fn
* @return {Router} for chaining
* @api public
* @return {app} for chaining
* @public
*/
Router.prototype.param = function(name, fn){
proto.param = function param(name, fn) {
// param logic
if ('function' == typeof name) {
if (typeof name === 'function') {
deprecate('router.param(fn): Refactor to use path params');
this._params.push(name);
return;
}
// apply param functions
var params = this._params
, len = params.length
, ret;
var params = this._params;
var len = params.length;
var ret;
if (name[0] === ':') {
deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead');
name = name.substr(1);
}
for (var i = 0; i < len; ++i) {
if (ret = params[i](name, fn)) {
@ -72,265 +128,518 @@ Router.prototype.param = function(name, fn){
};
/**
* Route dispatcher aka the route "middleware".
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @param {Function} next
* @api private
* Dispatch a req, res into the router.
* @private
*/
Router.prototype._dispatch = function(req, res, next){
var params = this.params
, self = this;
proto.handle = function handle(req, res, out) {
var self = this;
debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
debug('dispatching %s %s', req.method, req.url);
// route dispatch
(function pass(i, err){
var paramCallbacks
, paramIndex = 0
, paramVal
, route
, keys
, key;
var search = 1 + req.url.indexOf('?');
var pathlength = search ? search - 1 : req.url.length;
var fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://');
var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '';
var idx = 0;
var removed = '';
var slashAdded = false;
var paramcalled = {};
// match next route
function nextRoute(err) {
pass(req._route_index + 1, err);
}
// match route
req.route = route = self.matchRequest(req, i);
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res, next);
// no route
if (!route) return next(err);
debug('matched %s %s', route.method, route.path);
// we have a route
// start at param 0
req.params = route.params;
keys = route.keys;
i = 0;
// param callbacks
function param(err) {
paramIndex = 0;
key = keys[i++];
paramVal = key && req.params[key.name];
paramCallbacks = key && params[key.name];
try {
if ('route' == err) {
nextRoute();
} else if (err) {
i = 0;
callbacks(err);
} else if (paramCallbacks && undefined !== paramVal) {
paramCallback();
} else if (key) {
param();
} else {
i = 0;
callbacks();
}
} catch (err) {
param(err);
}
};
param(err);
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
if (err || !fn) return param(err);
fn(req, res, paramCallback, paramVal, key.name);
}
// invoke route callbacks
function callbacks(err) {
var fn = route.callbacks[i++];
try {
if ('route' == err) {
nextRoute();
} else if (err && fn) {
if (fn.length < 4) return callbacks(err);
fn(err, req, res, callbacks);
} else if (fn) {
if (fn.length < 4) return fn(req, res, callbacks);
callbacks();
} else {
nextRoute(err);
}
} catch (err) {
callbacks(err);
}
}
})(0);
};
/**
* Respond to __OPTIONS__ method.
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @api private
*/
Router.prototype._options = function(req, res, next){
var path = parseUrl(req).pathname
, body = this._optionsFor(path).join(',');
if (!body) return next();
res.set('Allow', body).send(body);
};
/**
* Return an array of HTTP verbs or "options" for `path`.
*
* @param {String} path
* @return {Array}
* @api private
*/
Router.prototype._optionsFor = function _optionsFor(path) {
// store options for OPTIONS request
// only used if OPTIONS request
var options = [];
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
// middleware and routes
var stack = self.stack;
if (method === 'options') continue;
// manage inter-router variables
var parentParams = req.params;
var parentUrl = req.baseUrl || '';
var done = restore(out, req, 'baseUrl', 'next', 'params');
var routes = this.map[method];
// setup next layer
req.next = next;
// HEAD methods include GET routes
if (!routes && method === 'head') {
routes = this.map.get;
// for options requests, respond with a default if nothing else responds
if (req.method === 'OPTIONS') {
done = wrap(done, function(old, err) {
if (err || options.length === 0) return old(err);
sendOptionsResponse(res, options, old);
});
}
// setup basic req values
req.baseUrl = parentUrl;
req.originalUrl = req.originalUrl || req.url;
next();
function next(err) {
var layerError = err === 'route'
? null
: err;
// remove added slash
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
if (!routes) continue;
// restore altered req.url
if (removed.length !== 0) {
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
removed = '';
}
for (var j = 0; j < routes.length; j++) {
if (routes[j].match(path)) {
options.push(method.toUpperCase());
break;
// no more matching layers
if (idx >= stack.length) {
setImmediate(done, layerError);
return;
}
// get pathname of request
var path = getPathname(req);
if (path == null) {
return done(layerError);
}
// find next matching layer
var layer;
var match;
var route;
while (match !== true && idx < stack.length) {
layer = stack[idx++];
match = matchLayer(layer, path);
route = layer.route;
if (typeof match !== 'boolean') {
// hold on to layerError
layerError = layerError || match;
}
if (match !== true) {
continue;
}
if (!route) {
// process non-route handlers normally
continue;
}
if (layerError) {
// routes do not match with a pending error
match = false;
continue;
}
var method = req.method;
var has_method = route._handles_method(method);
// build up automatic options response
if (!has_method && method === 'OPTIONS') {
appendMethods(options, route._options());
}
// don't even bother matching route
if (!has_method && method !== 'HEAD') {
match = false;
continue;
}
}
}
return options.sort();
};
// no match
if (match !== true) {
return done(layerError);
}
/**
* Attempt to match a route for `req`
* with optional starting index of `i`
* defaulting to 0.
*
* @param {IncomingMessage} req
* @param {Number} i
* @return {Route}
* @api private
*/
// store route for dispatch on change
if (route) {
req.route = route;
}
Router.prototype.matchRequest = function(req, i, head){
var method = req.method.toLowerCase()
, url = parseUrl(req)
, path = url.pathname
, routes = this.map
, i = i || 0
, route;
// Capture one-time layer values
req.params = self.mergeParams
? mergeParams(layer.params, parentParams)
: layer.params;
var layerPath = layer.path;
// HEAD support
if (!head && 'head' == method) {
route = this.matchRequest(req, i, true);
if (route) return route;
method = 'get';
}
// routes for this method
if (routes = routes[method]) {
// matching routes
for (var len = routes.length; i < len; ++i) {
route = routes[i];
if (route.match(path)) {
req._route_index = i;
return route;
// this should be done for the layer
self.process_params(layer, paramcalled, req, res, function (err) {
if (err) {
return next(layerError || err);
}
if (route) {
return layer.handle_request(req, res, next);
}
trim_prefix(layer, layerError, layerPath, path);
});
}
function trim_prefix(layer, layerError, layerPath, path) {
var c = path[layerPath.length];
if (c && '/' !== c && '.' !== c) return next(layerError);
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
if (layerPath.length !== 0) {
debug('trim prefix (%s) from url %s', layerPath, req.url);
removed = layerPath;
req.url = protohost + req.url.substr(protohost.length + removed.length);
// Ensure leading slash
if (!fqdn && req.url[0] !== '/') {
req.url = '/' + req.url;
slashAdded = true;
}
// Setup base URL (no trailing slash)
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
? removed.substring(0, removed.length - 1)
: removed);
}
debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
if (layerError) {
layer.handle_error(layerError, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
/**
* Attempt to match a route for `method`
* and `url` with optional starting
* index of `i` defaulting to 0.
*
* @param {String} method
* @param {String} url
* @param {Number} i
* @return {Route}
* @api private
* Process any parameters for the layer.
* @private
*/
Router.prototype.match = function(method, url, i, head){
var req = { method: method, url: url };
return this.matchRequest(req, i, head);
proto.process_params = function process_params(layer, called, req, res, done) {
var params = this.params;
// captured parameters from the layer, keys and values
var keys = layer.keys;
// fast track
if (!keys || keys.length === 0) {
return done();
}
var i = 0;
var name;
var paramIndex = 0;
var key;
var paramVal;
var paramCallbacks;
var paramCalled;
// process params in order
// param callbacks can be async
function param(err) {
if (err) {
return done(err);
}
if (i >= keys.length ) {
return done();
}
paramIndex = 0;
key = keys[i++];
if (!key) {
return done();
}
name = key.name;
paramVal = req.params[name];
paramCallbacks = params[name];
paramCalled = called[name];
if (paramVal === undefined || !paramCallbacks) {
return param();
}
// param previously called with same value or error occurred
if (paramCalled && (paramCalled.match === paramVal
|| (paramCalled.error && paramCalled.error !== 'route'))) {
// restore value
req.params[name] = paramCalled.value;
// next param
return param(paramCalled.error);
}
called[name] = paramCalled = {
error: null,
match: paramVal,
value: paramVal
};
paramCallback();
}
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
// store updated value
paramCalled.value = req.params[key.name];
if (err) {
// store error
paramCalled.error = err;
param(err);
return;
}
if (!fn) return param();
try {
fn(req, res, paramCallback, paramVal, key.name);
} catch (e) {
paramCallback(e);
}
}
param();
};
/**
* Route `method`, `path`, and one or more callbacks.
* Use the given middleware function, with optional path, defaulting to "/".
*
* Use (like `.all`) will run for any http METHOD, but it will not add
* handlers for those methods so OPTIONS requests will not consider `.use`
* functions even if they could respond.
*
* The other difference is that _route_ path is stripped and not visible
* to the handler function. The main effect of this feature is that mounted
* handlers can operate without any code changes regardless of the "prefix"
* pathname.
*
* @public
*/
proto.use = function use(fn) {
var offset = 0;
var path = '/';
// default path to '/'
// disambiguate router.use([fn])
if (typeof fn !== 'function') {
var arg = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
}
var callbacks = flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires middleware functions');
}
for (var i = 0; i < callbacks.length; i++) {
var fn = callbacks[i];
if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
}
// add the middleware
debug('use %s %s', path, fn.name || '<anonymous>');
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: false,
end: false
}, fn);
layer.route = undefined;
this.stack.push(layer);
}
return this;
};
/**
* Create a new Route for the given path.
*
* Each route contains a separate middleware stack and VERB handlers.
*
* See the Route api documentation for details on adding handlers
* and middleware to routes.
*
* @param {String} method
* @param {String} path
* @param {Function} callback...
* @return {Router} for chaining
* @api private
* @return {Route}
* @public
*/
Router.prototype.route = function(method, path, callbacks){
var method = method.toLowerCase()
, callbacks = utils.flatten([].slice.call(arguments, 2));
proto.route = function route(path) {
var route = new Route(path);
// ensure path was given
if (!path) throw new Error('Router#' + method + '() requires a path');
// ensure all callbacks are functions
callbacks.forEach(function(fn){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
});
// create the route
debug('defined %s %s', method, path);
var route = new Route(method, path, callbacks, {
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict
});
strict: this.strict,
end: true
}, route.dispatch.bind(route));
// add it
(this.map[method] = this.map[method] || []).push(route);
return this;
layer.route = route;
this.stack.push(layer);
return route;
};
Router.prototype.all = function(path) {
var self = this;
var args = [].slice.call(arguments);
methods.forEach(function(method){
self.route.apply(self, [method].concat(args));
});
return this;
};
methods.forEach(function(method){
Router.prototype[method] = function(path){
var args = [method].concat([].slice.call(arguments));
this.route.apply(this, args);
// create Router#VERB functions
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
// append methods to a list of methods
function appendMethods(list, addition) {
for (var i = 0; i < addition.length; i++) {
var method = addition[i];
if (list.indexOf(method) === -1) {
list.push(method);
}
}
}
// get pathname of request
function getPathname(req) {
try {
return parseUrl(req).pathname;
} catch (err) {
return undefined;
}
}
// get type for error message
function gettype(obj) {
var type = typeof obj;
if (type !== 'object') {
return type;
}
// inspect [[Class]] for objects
return toString.call(obj)
.replace(objectRegExp, '$1');
}
/**
* Match path to a layer.
*
* @param {Layer} layer
* @param {string} path
* @private
*/
function matchLayer(layer, path) {
try {
return layer.match(path);
} catch (err) {
return err;
}
}
// merge params with parent params
function mergeParams(params, parent) {
if (typeof parent !== 'object' || !parent) {
return params;
}
// make copy of parent for base
var obj = mixin({}, parent);
// simple non-numeric merging
if (!(0 in params) || !(0 in parent)) {
return mixin(obj, params);
}
var i = 0;
var o = 0;
// determine numeric gaps
while (i in params) {
i++;
}
while (o in parent) {
o++;
}
// offset numeric indices in params before merge
for (i--; i >= 0; i--) {
params[i + o] = params[i];
// create holes for the merge when necessary
if (i < o) {
delete params[i];
}
}
return mixin(obj, params);
}
// restore obj props after function
function restore(fn, obj) {
var props = new Array(arguments.length - 2);
var vals = new Array(arguments.length - 2);
for (var i = 0; i < props.length; i++) {
props[i] = arguments[i + 2];
vals[i] = obj[props[i]];
}
return function(err){
// restore vals
for (var i = 0; i < props.length; i++) {
obj[props[i]] = vals[i];
}
return fn.apply(this, arguments);
};
}
// send an OPTIONS response
function sendOptionsResponse(res, options, next) {
try {
var body = options.join(',');
res.set('Allow', body);
res.send(body);
} catch (err) {
next(err);
}
}
// wrap a function
function wrap(old, fn) {
return function proxy() {
var args = new Array(arguments.length + 1);
args[0] = old;
for (var i = 0, len = arguments.length; i < len; i++) {
args[i + 1] = arguments[i];
}
fn.apply(this, args);
};
}

View File

@ -1,78 +1,210 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var utils = require('../utils');
var debug = require('debug')('express:router:route');
var flatten = require('array-flatten');
var Layer = require('./layer');
var methods = require('methods');
/**
* Expose `Route`.
* Module variables.
* @private
*/
var slice = Array.prototype.slice;
var toString = Object.prototype.toString;
/**
* Module exports.
* @public
*/
module.exports = Route;
/**
* Initialize `Route` with the given HTTP `method`, `path`,
* and an array of `callbacks` and `options`.
* Initialize `Route` with the given `path`,
*
* Options:
*
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
*
* @param {String} method
* @param {String} path
* @param {Array} callbacks
* @param {Object} options.
* @api private
* @public
*/
function Route(method, path, callbacks, options) {
options = options || {};
function Route(path) {
this.path = path;
this.method = method;
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
this.stack = [];
debug('new %s', path);
// route handlers for various http methods
this.methods = {};
}
/**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
* Determine if the route handles a given method.
* @private
*/
Route.prototype.match = function(path){
var keys = this.keys
, params = this.params = []
, m = this.regexp.exec(path);
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
try {
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
} catch(e) {
var err = new Error("Failed to decode param '" + m[i] + "'");
err.status = 400;
throw err;
}
if (key) {
params[key.name] = val;
} else {
params.push(val);
}
Route.prototype._handles_method = function _handles_method(method) {
if (this.methods._all) {
return true;
}
return true;
var name = method.toLowerCase();
if (name === 'head' && !this.methods['head']) {
name = 'get';
}
return Boolean(this.methods[name]);
};
/**
* @return {Array} supported HTTP methods
* @private
*/
Route.prototype._options = function _options() {
var methods = Object.keys(this.methods);
// append automatic head
if (this.methods.get && !this.methods.head) {
methods.push('head');
}
for (var i = 0; i < methods.length; i++) {
// make upper case
methods[i] = methods[i].toUpperCase();
}
return methods;
};
/**
* dispatch req, res into this route
* @private
*/
Route.prototype.dispatch = function dispatch(req, res, done) {
var idx = 0;
var stack = this.stack;
if (stack.length === 0) {
return done();
}
var method = req.method.toLowerCase();
if (method === 'head' && !this.methods['head']) {
method = 'get';
}
req.route = this;
next();
function next(err) {
if (err && err === 'route') {
return done();
}
var layer = stack[idx++];
if (!layer) {
return done(err);
}
if (layer.method && layer.method !== method) {
return next(err);
}
if (err) {
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
/**
* Add a handler for all HTTP verbs to this route.
*
* Behaves just like middleware and can respond or call `next`
* to continue processing.
*
* You can use multiple `.all` call to add multiple handlers.
*
* function check_something(req, res, next){
* next();
* };
*
* function validate_user(req, res, next){
* next();
* };
*
* route
* .all(validate_user)
* .all(check_something)
* .get(function(req, res, next){
* res.send('hello world');
* });
*
* @param {function} handler
* @return {Route} for chaining
* @api public
*/
Route.prototype.all = function all() {
var handles = flatten(slice.call(arguments));
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.all() requires callback functions but got a ' + type;
throw new TypeError(msg);
}
var layer = Layer('/', {}, handle);
layer.method = undefined;
this.methods._all = true;
this.stack.push(layer);
}
return this;
};
methods.forEach(function(method){
Route.prototype[method] = function(){
var handles = flatten(slice.call(arguments));
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
}
debug('%s %s', method, this.path);
var layer = Layer('/', {}, handle);
layer.method = method;
this.methods[method] = true;
this.stack.push(layer);
}
return this;
};
});

268
node_modules/express/lib/utils.js generated vendored
View File

@ -5,21 +5,23 @@
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @api private
*/
var contentDisposition = require('content-disposition');
var contentType = require('content-type');
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var mime = require('send').mime;
var basename = require('path').basename;
var etag = require('etag');
var mime = require('connect').mime;
var proxyaddr = require('proxy-addr');
/**
* toString ref.
*/
var toString = {}.toString;
var qs = require('qs');
var querystring = require('querystring');
/**
* Return strong ETag for `body`.
@ -55,25 +57,6 @@ exports.wetag = function wetag(body, encoding){
return etag(buf, {weak: true});
};
/**
* Make `locals()` bound to the given `obj`.
*
* This is used for `app.locals` and `res.locals`.
*
* @param {Object} obj
* @return {Function}
* @api private
*/
exports.locals = function(){
function locals(obj){
for (var key in obj) locals[key] = obj[key];
return obj;
};
return locals;
};
/**
* Check if `path` looks absolute.
*
@ -96,18 +79,8 @@ exports.isAbsolute = function(path){
* @api private
*/
exports.flatten = function(arr, ret){
var ret = ret || []
, len = arr.length;
for (var i = 0; i < len; ++i) {
if (Array.isArray(arr[i])) {
exports.flatten(arr[i], ret);
} else {
ret.push(arr[i]);
}
}
return ret;
};
exports.flatten = deprecate.function(flatten,
'utils.flatten: use array-flatten npm module instead');
/**
* Normalize the given `type`, for example "html" becomes "text/html".
@ -142,126 +115,16 @@ exports.normalizeTypes = function(types){
};
/**
* Return the acceptable type in `types`, if any.
* Generate Content-Disposition header appropriate for the filename.
* non-ascii filenames are urlencoded and a filename* parameter is added
*
* @param {Array} types
* @param {String} str
* @param {String} filename
* @return {String}
* @api private
*/
exports.acceptsArray = function(types, str){
// accept anything when Accept is not present
if (!str) return types[0];
// parse
var accepted = exports.parseAccept(str)
, normalized = exports.normalizeTypes(types)
, len = accepted.length;
for (var i = 0; i < len; ++i) {
for (var j = 0, jlen = types.length; j < jlen; ++j) {
if (exports.accept(normalized[j], accepted[i])) {
return types[j];
}
}
}
};
/**
* Check if `type(s)` are acceptable based on
* the given `str`.
*
* @param {String|Array} type(s)
* @param {String} str
* @return {Boolean|String}
* @api private
*/
exports.accepts = function(type, str){
if ('string' == typeof type) type = type.split(/ *, */);
return exports.acceptsArray(type, str);
};
/**
* Check if `type` array is acceptable for `other`.
*
* @param {Object} type
* @param {Object} other
* @return {Boolean}
* @api private
*/
exports.accept = function(type, other){
var t = type.value.split('/');
return (t[0] == other.type || '*' == other.type)
&& (t[1] == other.subtype || '*' == other.subtype)
&& paramsEqual(type.params, other.params);
};
/**
* Check if accept params are equal.
*
* @param {Object} a
* @param {Object} b
* @return {Boolean}
* @api private
*/
function paramsEqual(a, b){
return !Object.keys(a).some(function(k) {
return a[k] != b[k];
});
}
/**
* Parse accept `str`, returning
* an array objects containing
* `.type` and `.subtype` along
* with the values provided by
* `parseQuality()`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseAccept = function(str){
return exports
.parseParams(str)
.map(function(obj){
var parts = obj.value.split('/');
obj.type = parts[0];
obj.subtype = parts[1];
return obj;
});
};
/**
* Parse quality `str`, returning an
* array of objects with `.value`,
* `.quality` and optional `.params`
*
* @param {String} str
* @return {Array}
* @api private
*/
exports.parseParams = function(str){
return str
.split(/ *, */)
.map(acceptParams)
.filter(function(obj){
return obj.quality;
})
.sort(function(a, b){
if (a.quality === b.quality) {
return a.originalIndex - b.originalIndex;
} else {
return b.quality - a.quality;
}
});
};
exports.contentDisposition = deprecate.function(contentDisposition,
'utils.contentDisposition: use content-disposition npm module instead');
/**
* Parse accept params `str` returning an
@ -289,45 +152,6 @@ function acceptParams(str, index) {
return ret;
}
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private
*/
exports.pathRegexp = function(path, keys, sensitive, strict) {
if (toString.call(path) == '[object RegExp]') return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '')
+ (star ? '(/*)?' : '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
/**
* Compile "etag" value to function.
*
@ -362,6 +186,41 @@ exports.compileETag = function(val) {
return fn;
}
/**
* Compile "query parser" value to function.
*
* @param {String|Function} val
* @return {Function}
* @api private
*/
exports.compileQueryParser = function compileQueryParser(val) {
var fn;
if (typeof val === 'function') {
return val;
}
switch (val) {
case true:
fn = querystring.parse;
break;
case false:
fn = newObject;
break;
case 'extended':
fn = parseExtendedQueryString;
break;
case 'simple':
fn = querystring.parse;
break;
default:
throw new TypeError('unknown value for query parser function: ' + val);
}
return fn;
}
/**
* Compile "proxy trust" value to function.
*
@ -414,3 +273,28 @@ exports.setCharset = function setCharset(type, charset) {
// format type
return contentType.format(parsed);
};
/**
* Parse an extended query string with qs.
*
* @return {Object}
* @private
*/
function parseExtendedQueryString(str) {
return qs.parse(str, {
allowDots: false,
allowPrototypes: true
});
}
/**
* Return new empty object.
*
* @return {Object}
* @api private
*/
function newObject() {
return {};
}

178
node_modules/express/lib/view.js generated vendored
View File

@ -1,18 +1,37 @@
/**
* Module dependencies.
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
var path = require('path')
, fs = require('fs')
, utils = require('./utils')
, dirname = path.dirname
, basename = path.basename
, extname = path.extname
, exists = fs.existsSync || path.existsSync
, join = path.join;
'use strict';
/**
* Expose `View`.
* Module dependencies.
* @private
*/
var debug = require('debug')('express:view');
var path = require('path');
var fs = require('fs');
var utils = require('./utils');
/**
* Module variables.
* @private
*/
var dirname = path.dirname;
var basename = path.basename;
var extname = path.extname;
var join = path.join;
var resolve = path.resolve;
/**
* Module exports.
* @public
*/
module.exports = View;
@ -26,52 +45,129 @@ module.exports = View;
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* @param {String} name
* @param {Object} options
* @api private
* @param {string} name
* @param {object} options
* @public
*/
function View(name, options) {
options = options || {};
var opts = options || {};
this.defaultEngine = opts.defaultEngine;
this.ext = extname(name);
this.name = name;
this.root = options.root;
var engines = options.engines;
this.defaultEngine = options.defaultEngine;
var ext = this.ext = extname(name);
if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
this.path = this.lookup(name);
this.root = opts.root;
if (!this.ext && !this.defaultEngine) {
throw new Error('No default engine was specified and no extension was provided.');
}
var fileName = name;
if (!this.ext) {
// get extension from default engine name
this.ext = this.defaultEngine[0] !== '.'
? '.' + this.defaultEngine
: this.defaultEngine;
fileName += this.ext;
}
if (!opts.engines[this.ext]) {
// load engine
opts.engines[this.ext] = require(this.ext.substr(1)).__express;
}
// store loaded engine
this.engine = opts.engines[this.ext];
// lookup path
this.path = this.lookup(fileName);
}
/**
* Lookup view by the given `path`
* Lookup view by the given `name`
*
* @param {String} path
* @return {String}
* @api private
* @param {string} name
* @private
*/
View.prototype.lookup = function(path){
var ext = this.ext;
View.prototype.lookup = function lookup(name) {
var path;
var roots = [].concat(this.root);
// <path>.<engine>
if (!utils.isAbsolute(path)) path = join(this.root, path);
if (exists(path)) return path;
debug('lookup "%s"', name);
// <path>/index.<engine>
path = join(dirname(path), basename(path, ext), 'index' + ext);
if (exists(path)) return path;
for (var i = 0; i < roots.length && !path; i++) {
var root = roots[i];
// resolve the path
var loc = resolve(root, name);
var dir = dirname(loc);
var file = basename(loc);
// resolve the file
path = this.resolve(dir, file);
}
return path;
};
/**
* Render with the given `options` and callback `fn(err, str)`.
* Render with the given options.
*
* @param {Object} options
* @param {Function} fn
* @api private
* @param {object} options
* @param {function} callback
* @private
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
View.prototype.render = function render(options, callback) {
debug('render "%s"', this.path);
this.engine(this.path, options, callback);
};
/**
* Resolve the file within the given directory.
*
* @param {string} dir
* @param {string} file
* @private
*/
View.prototype.resolve = function resolve(dir, file) {
var ext = this.ext;
// <path>.<ext>
var path = join(dir, file);
var stat = tryStat(path);
if (stat && stat.isFile()) {
return path;
}
// <path>/index.<ext>
path = join(dir, basename(file, ext), 'index' + ext);
stat = tryStat(path);
if (stat && stat.isFile()) {
return path;
}
};
/**
* Return a stat, maybe.
*
* @param {string} path
* @return {fs.Stats}
* @private
*/
function tryStat(path) {
debug('stat "%s"', path);
try {
return fs.statSync(path);
} catch (e) {
return undefined;
}
}

View File

@ -1,40 +0,0 @@
0.5.0 / 2014-10-11
==================
* Add `parse` function
0.4.0 / 2014-09-21
==================
* Expand non-Unicode `filename` to the full ISO-8859-1 charset
0.3.0 / 2014-09-20
==================
* Add `fallback` option
* Add `type` option
0.2.0 / 2014-09-19
==================
* Reduce ambiguity of file names with hex escape in buggy browsers
0.1.2 / 2014-09-19
==================
* Fix periodic invalid Unicode filename header
0.1.1 / 2014-09-19
==================
* Fix invalid characters appearing in `filename*` parameter
0.1.0 / 2014-09-18
==================
* Make the `filename` argument optional
0.0.0 / 2014-09-18
==================
* Initial release

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,141 +0,0 @@
# content-disposition
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Create and parse HTTP `Content-Disposition` header
## Installation
```sh
$ npm install content-disposition
```
## API
```js
var contentDisposition = require('content-disposition')
```
### contentDisposition(filename, options)
Create an attachment `Content-Disposition` header value using the given file name,
if supplied. The `filename` is optional and if no file name is desired, but you
want to specify `options`, set `filename` to `undefined`.
```js
res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf'))
```
**note** HTTP headers are of the ISO-8859-1 character set. If you are writing this
header through a means different from `setHeader` in Node.js, you'll want to specify
the `'binary'` encoding in Node.js.
#### Options
`contentDisposition` accepts these properties in the options object.
##### fallback
If the `filename` option is outside ISO-8859-1, then the file name is actually
stored in a supplemental field for clients that support Unicode file names and
a ISO-8859-1 version of the file name is automatically generated.
This specifies the ISO-8859-1 file name to override the automatic generation or
disables the generation all together, defaults to `true`.
- A string will specify the ISO-8859-1 file name to use in place of automatic
generation.
- `false` will disable including a ISO-8859-1 file name and only include the
Unicode version (unless the file name is already ISO-8859-1).
- `true` will enable automatic generation if the file name is outside ISO-8859-1.
If the `filename` option is ISO-8859-1 and this option is specified and has a
different value, then the `filename` option is encoded in the extended field
and this set as the fallback field, even though they are both ISO-8859-1.
##### type
Specifies the disposition type, defaults to `"attachment"`. This can also be
`"inline"`, or any other value (all values except inline are treated like
`attachment`, but can convey additional information if both parties agree to
it). The type is normalized to lower-case.
### contentDisposition.parse(string)
```js
var disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt"');
```
Parse a `Content-Disposition` header string. This automatically handles extended
("Unicode") parameters by decoding them and providing them under the standard
parameter name. This will return an object with the following properties (examples
are shown for the string `'attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt'`):
- `type`: The disposition type (always lower case). Example: `'attachment'`
- `parameters`: An object of the parameters in the disposition (name of parameter
always lower case and extended versions replace non-extended versions). Example:
`{filename: "€ rates.txt"}`
## Examples
### Send a file for download
```js
var contentDisposition = require('content-disposition')
var destroy = require('destroy')
var http = require('http')
var onFinished = require('on-finished')
var filePath = '/path/to/public/plans.pdf'
http.createServer(function onRequest(req, res) {
// set headers
res.setHeader('Content-Type', 'application/pdf')
res.setHeader('Content-Disposition', contentDisposition(filePath))
// send file
var stream = fs.createReadStream(filePath)
stream.pipe(res)
onFinished(res, function (err) {
destroy(stream)
})
})
```
## Testing
```sh
$ npm test
```
## References
- [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1][rfc-2616]
- [RFC 5987: Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters][rfc-5987]
- [RFC 6266: Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)][rfc-6266]
- [Test Cases for HTTP Content-Disposition header field (RFC 6266) and the Encodings defined in RFCs 2047, 2231 and 5987][tc-2231]
[rfc-2616]: https://tools.ietf.org/html/rfc2616
[rfc-5987]: https://tools.ietf.org/html/rfc5987
[rfc-6266]: https://tools.ietf.org/html/rfc6266
[tc-2231]: http://greenbytes.de/tech/tc2231/
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/content-disposition.svg?style=flat
[npm-url]: https://npmjs.org/package/content-disposition
[node-version-image]: https://img.shields.io/node/v/content-disposition.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/content-disposition.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/content-disposition
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-disposition.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master
[downloads-image]: https://img.shields.io/npm/dm/content-disposition.svg?style=flat
[downloads-url]: https://npmjs.org/package/content-disposition

View File

@ -1,443 +0,0 @@
/*!
* content-disposition
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = contentDisposition
module.exports.parse = parse
/**
* Module dependencies.
*/
var basename = require('path').basename
/**
* RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%")
*/
var encodeUriAttrCharRegExp = /[\x00-\x20"'\(\)*,\/:;<=>?@\[\\\]\{\}\x7f]/g
/**
* RegExp to match percent encoding escape.
*/
var hexEscapeRegExp = /%[0-9A-Fa-f]{2}/
var hexEscapeReplaceRegExp = /%([0-9A-Fa-f]{2})/g
/**
* RegExp to match non-latin1 characters.
*/
var nonLatin1RegExp = /[^\x20-\x7e\xa0-\xff]/g
/**
* RegExp to match quoted-pair in RFC 2616
*
* quoted-pair = "\" CHAR
* CHAR = <any US-ASCII character (octets 0 - 127)>
*/
var qescRegExp = /\\([\u0000-\u007f])/g;
/**
* RegExp to match chars that must be quoted-pair in RFC 2616
*/
var quoteRegExp = /([\\"])/g
/**
* RegExp for various RFC 2616 grammar
*
* parameter = token "=" ( token | quoted-string )
* token = 1*<any CHAR except CTLs or separators>
* separators = "(" | ")" | "<" | ">" | "@"
* | "," | ";" | ":" | "\" | <">
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
* quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
* qdtext = <any TEXT except <">>
* quoted-pair = "\" CHAR
* CHAR = <any US-ASCII character (octets 0 - 127)>
* TEXT = <any OCTET except CTLs, but including LWS>
* LWS = [CRLF] 1*( SP | HT )
* CRLF = CR LF
* CR = <US-ASCII CR, carriage return (13)>
* LF = <US-ASCII LF, linefeed (10)>
* SP = <US-ASCII SP, space (32)>
* HT = <US-ASCII HT, horizontal-tab (9)>
* CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
* OCTET = <any 8-bit sequence of data>
*/
var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g
var textRegExp = /^[\x20-\x7e\x80-\xff]+$/
var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
/**
* RegExp for various RFC 5987 grammar
*
* ext-value = charset "'" [ language ] "'" value-chars
* charset = "UTF-8" / "ISO-8859-1" / mime-charset
* mime-charset = 1*mime-charsetc
* mime-charsetc = ALPHA / DIGIT
* / "!" / "#" / "$" / "%" / "&"
* / "+" / "-" / "^" / "_" / "`"
* / "{" / "}" / "~"
* language = ( 2*3ALPHA [ extlang ] )
* / 4ALPHA
* / 5*8ALPHA
* extlang = *3( "-" 3ALPHA )
* value-chars = *( pct-encoded / attr-char )
* pct-encoded = "%" HEXDIG HEXDIG
* attr-char = ALPHA / DIGIT
* / "!" / "#" / "$" / "&" / "+" / "-" / "."
* / "^" / "_" / "`" / "|" / "~"
*/
var extValueRegExp = /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+\-\.^_`|~])+)$/
/**
* RegExp for various RFC 6266 grammar
*
* disposition-type = "inline" | "attachment" | disp-ext-type
* disp-ext-type = token
* disposition-parm = filename-parm | disp-ext-parm
* filename-parm = "filename" "=" value
* | "filename*" "=" ext-value
* disp-ext-parm = token "=" value
* | ext-token "=" ext-value
* ext-token = <the characters in token, followed by "*">
*/
var dispositionTypeRegExp = /^([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *(?:$|;)/
/**
* Create an attachment Content-Disposition header.
*
* @param {string} [filename]
* @param {object} [options]
* @param {string} [options.type=attachment]
* @param {string|boolean} [options.fallback=true]
* @return {string}
* @api public
*/
function contentDisposition(filename, options) {
var opts = options || {}
// get type
var type = opts.type || 'attachment'
// get parameters
var params = createparams(filename, opts.fallback)
// format into string
return format(new ContentDisposition(type, params))
}
/**
* Create parameters object from filename and fallback.
*
* @param {string} [filename]
* @param {string|boolean} [fallback=true]
* @return {object}
* @api private
*/
function createparams(filename, fallback) {
if (filename === undefined) {
return
}
var params = {}
if (typeof filename !== 'string') {
throw new TypeError('filename must be a string')
}
// fallback defaults to true
if (fallback === undefined) {
fallback = true
}
if (typeof fallback !== 'string' && typeof fallback !== 'boolean') {
throw new TypeError('fallback must be a string or boolean')
}
if (typeof fallback === 'string' && nonLatin1RegExp.test(fallback)) {
throw new TypeError('fallback must be ISO-8859-1 string')
}
// restrict to file base name
var name = basename(filename)
// determine if name is suitable for quoted string
var isQuotedString = textRegExp.test(name)
// generate fallback name
var fallbackName = typeof fallback !== 'string'
? fallback && getlatin1(name)
: basename(fallback)
var hasFallback = typeof fallbackName === 'string' && fallbackName !== name
// set extended filename parameter
if (hasFallback || !isQuotedString || hexEscapeRegExp.test(name)) {
params['filename*'] = name
}
// set filename parameter
if (isQuotedString || hasFallback) {
params.filename = hasFallback
? fallbackName
: name
}
return params
}
/**
* Format object to Content-Disposition header.
*
* @param {object} obj
* @param {string} obj.type
* @param {object} [obj.parameters]
* @return {string}
* @api private
*/
function format(obj) {
var parameters = obj.parameters
var type = obj.type
if (!type || typeof type !== 'string' || !tokenRegExp.test(type)) {
throw new TypeError('invalid type')
}
// start with normalized type
var string = String(type).toLowerCase()
// append parameters
if (parameters && typeof parameters === 'object') {
var param
var params = Object.keys(parameters).sort()
for (var i = 0; i < params.length; i++) {
param = params[i]
var val = param.substr(-1) === '*'
? ustring(parameters[param])
: qstring(parameters[param])
string += '; ' + param + '=' + val
}
}
return string
}
/**
* Decode a RFC 6987 field value (gracefully).
*
* @param {string} str
* @return {string}
* @api private
*/
function decodefield(str) {
var match = extValueRegExp.exec(str)
if (!match) {
throw new TypeError('invalid extended field value')
}
var charset = match[1].toLowerCase()
var encoded = match[2]
var value
// to binary string
var binary = encoded.replace(hexEscapeReplaceRegExp, pdecode)
switch (charset) {
case 'iso-8859-1':
value = getlatin1(binary)
break
case 'utf-8':
value = new Buffer(binary, 'binary').toString('utf8')
break
default:
throw new TypeError('unsupported charset in extended field')
}
return value
}
/**
* Get ISO-8859-1 version of string.
*
* @param {string} val
* @return {string}
* @api private
*/
function getlatin1(val) {
// simple Unicode -> ISO-8859-1 transformation
return String(val).replace(nonLatin1RegExp, '?')
}
/**
* Parse Content-Disposition header string.
*
* @param {string} string
* @return {object}
* @api private
*/
function parse(string) {
if (!string || typeof string !== 'string') {
throw new TypeError('argument string is required')
}
var match = dispositionTypeRegExp.exec(string)
if (!match) {
throw new TypeError('invalid type format')
}
// normalize type
var index = match[0].length
var type = match[1].toLowerCase()
var key
var names = []
var params = {}
var value
// calculate index to start at
index = paramRegExp.lastIndex = match[0].substr(-1) === ';'
? index - 1
: index
// match parameters
while (match = paramRegExp.exec(string)) {
if (match.index !== index) {
throw new TypeError('invalid parameter format')
}
index += match[0].length
key = match[1].toLowerCase()
value = match[2]
if (names.indexOf(key) !== -1) {
throw new TypeError('invalid duplicate parameter')
}
names.push(key)
if (key.indexOf('*') + 1 === key.length) {
// decode extended value
key = key.slice(0, -1)
value = decodefield(value)
// overwrite existing value
params[key] = value
continue
}
if (typeof params[key] === 'string') {
continue
}
if (value[0] === '"') {
// remove quotes and escapes
value = value
.substr(1, value.length - 2)
.replace(qescRegExp, '$1')
}
params[key] = value
}
if (index !== -1 && index !== string.length) {
throw new TypeError('invalid parameter format')
}
return new ContentDisposition(type, params)
}
/**
* Percent decode a single character.
*
* @param {string} str
* @param {string} hex
* @return {string}
* @api private
*/
function pdecode(str, hex) {
return String.fromCharCode(parseInt(hex, 16))
}
/**
* Percent encode a single character.
*
* @param {string} char
* @return {string}
* @api private
*/
function pencode(char) {
var hex = String(char)
.charCodeAt(0)
.toString(16)
.toUpperCase()
return hex.length === 1
? '%0' + hex
: '%' + hex
}
/**
* Quote a string for HTTP.
*
* @param {string} val
* @return {string}
* @api private
*/
function qstring(val) {
var str = String(val)
return '"' + str.replace(quoteRegExp, '\\$1') + '"'
}
/**
* Encode a Unicode string for HTTP (RFC 5987).
*
* @param {string} val
* @return {string}
* @api private
*/
function ustring(val) {
var str = String(val)
// percent encode as UTF-8
var encoded = encodeURIComponent(str)
.replace(encodeUriAttrCharRegExp, pencode)
return 'UTF-8\'\'' + encoded
}
/**
* Class for parsed Content-Disposition header for v8 optimization
*/
function ContentDisposition(type, parameters) {
this.type = type
this.parameters = parameters
}

View File

@ -1,65 +0,0 @@
{
"name": "content-disposition",
"description": "Create and parse Content-Disposition header",
"version": "0.5.0",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"license": "MIT",
"keywords": [
"content-disposition",
"http",
"rfc6266",
"res"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/content-disposition"
},
"devDependencies": {
"istanbul": "0.3.2",
"mocha": "~1.21.4"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "f3c915f0c9d9f5ec79713dba24c8c6181b73305d",
"bugs": {
"url": "https://github.com/jshttp/content-disposition/issues"
},
"homepage": "https://github.com/jshttp/content-disposition",
"_id": "content-disposition@0.5.0",
"_shasum": "4284fe6ae0630874639e44e80a418c2934135e9e",
"_from": "content-disposition@0.5.0",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "4284fe6ae0630874639e44e80a418c2934135e9e",
"tarball": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz"
}

View File

@ -1,9 +0,0 @@
1.0.1 / 2015-02-13
==================
* Improve missing `Content-Type` header error message
1.0.0 / 2015-02-01
==================
* Initial implementation, derived from `media-typer@0.3.0`

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2015 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,92 +0,0 @@
# content-type
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Create and parse HTTP Content-Type header according to RFC 7231
## Installation
```sh
$ npm install content-type
```
## API
```js
var contentType = require('content-type')
```
### contentType.parse(string)
```js
var obj = contentType.parse('image/svg+xml; charset=utf-8')
```
Parse a content type string. This will return an object with the following
properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
- `type`: The media type (the type and subtype, always lower case).
Example: `'image/svg+xml'`
- `parameters`: An object of the parameters in the media type (name of parameter
always lower case). Example: `{charset: 'utf-8'}`
Throws a `TypeError` if the string is missing or invalid.
### contentType.parse(req)
```js
var obj = contentType.parse(req)
```
Parse the `content-type` header from the given `req`. Short-cut for
`contentType.parse(req.headers['content-type'])`.
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
### contentType.parse(res)
```js
var obj = contentType.parse(res)
```
Parse the `content-type` header set on the given `res`. Short-cut for
`contentType.parse(res.getHeader('content-type'))`.
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
### contentType.format(obj)
```js
var str = contentType.format({type: 'image/svg+xml'})
```
Format an object into a content type string. This will return a string of the
content type for the given object with the following properties (examples are
shown that produce the string `'image/svg+xml; charset=utf-8'`):
- `type`: The media type (will be lower-cased). Example: `'image/svg+xml'`
- `parameters`: An object of the parameters in the media type (name of the
parameter will be lower-cased). Example: `{charset: 'utf-8'}`
Throws a `TypeError` if the object contains an invalid type or parameter names.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/content-type.svg
[npm-url]: https://npmjs.org/package/content-type
[node-version-image]: https://img.shields.io/node/v/content-type.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/content-type/master.svg
[travis-url]: https://travis-ci.org/jshttp/content-type
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-type/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/content-type
[downloads-image]: https://img.shields.io/npm/dm/content-type.svg
[downloads-url]: https://npmjs.org/package/content-type

View File

@ -1,214 +0,0 @@
/*!
* content-type
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
*
* parameter = token "=" ( token / quoted-string )
* token = 1*tchar
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
* / DIGIT / ALPHA
* ; any VCHAR, except delimiters
* quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
* qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
* obs-text = %x80-FF
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
*/
var paramRegExp = /; *([!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) */g
var textRegExp = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
var tokenRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
/**
* RegExp to match quoted-pair in RFC 7230 sec 3.2.6
*
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
* obs-text = %x80-FF
*/
var qescRegExp = /\\([\u000b\u0020-\u00ff])/g
/**
* RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
*/
var quoteRegExp = /([\\"])/g
/**
* RegExp to match type in RFC 6838
*
* media-type = type "/" subtype
* type = token
* subtype = token
*/
var typeRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+\/[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
/**
* Module exports.
* @public
*/
exports.format = format
exports.parse = parse
/**
* Format object to media type.
*
* @param {object} obj
* @return {string}
* @public
*/
function format(obj) {
if (!obj || typeof obj !== 'object') {
throw new TypeError('argument obj is required')
}
var parameters = obj.parameters
var type = obj.type
if (!type || !typeRegExp.test(type)) {
throw new TypeError('invalid type')
}
var string = type
// append parameters
if (parameters && typeof parameters === 'object') {
var param
var params = Object.keys(parameters).sort()
for (var i = 0; i < params.length; i++) {
param = params[i]
if (!tokenRegExp.test(param)) {
throw new TypeError('invalid parameter name')
}
string += '; ' + param + '=' + qstring(parameters[param])
}
}
return string
}
/**
* Parse media type to object.
*
* @param {string|object} string
* @return {Object}
* @public
*/
function parse(string) {
if (!string) {
throw new TypeError('argument string is required')
}
if (typeof string === 'object') {
// support req/res-like objects as argument
string = getcontenttype(string)
if (typeof string !== 'string') {
throw new TypeError('content-type header is missing from object');
}
}
if (typeof string !== 'string') {
throw new TypeError('argument string is required to be a string')
}
var index = string.indexOf(';')
var type = index !== -1
? string.substr(0, index).trim()
: string.trim()
if (!typeRegExp.test(type)) {
throw new TypeError('invalid media type')
}
var key
var match
var obj = new ContentType(type.toLowerCase())
var value
paramRegExp.lastIndex = index
while (match = paramRegExp.exec(string)) {
if (match.index !== index) {
throw new TypeError('invalid parameter format')
}
index += match[0].length
key = match[1].toLowerCase()
value = match[2]
if (value[0] === '"') {
// remove quotes and escapes
value = value
.substr(1, value.length - 2)
.replace(qescRegExp, '$1')
}
obj.parameters[key] = value
}
if (index !== -1 && index !== string.length) {
throw new TypeError('invalid parameter format')
}
return obj
}
/**
* Get content-type from req/res objects.
*
* @param {object}
* @return {Object}
* @private
*/
function getcontenttype(obj) {
if (typeof obj.getHeader === 'function') {
// res-like
return obj.getHeader('content-type')
}
if (typeof obj.headers === 'object') {
// req-like
return obj.headers && obj.headers['content-type']
}
}
/**
* Quote a string if necessary.
*
* @param {string} val
* @return {string}
* @private
*/
function qstring(val) {
var str = String(val)
// no need to quote tokens
if (tokenRegExp.test(str)) {
return str
}
if (str.length > 0 && !textRegExp.test(str)) {
throw new TypeError('invalid parameter value')
}
return '"' + str.replace(quoteRegExp, '\\$1') + '"'
}
/**
* Class to represent a content type.
* @private
*/
function ContentType(type) {
this.parameters = Object.create(null)
this.type = type
}

View File

@ -1,64 +0,0 @@
{
"name": "content-type",
"description": "Create and parse HTTP Content-Type header",
"version": "1.0.1",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"keywords": [
"content-type",
"http",
"req",
"res",
"rfc7231"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/content-type"
},
"devDependencies": {
"istanbul": "0.3.5",
"mocha": "~1.21.5"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --check-leaks --bail test/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
},
"gitHead": "3aa58f9c5a358a3634b8601602177888b4a477d8",
"bugs": {
"url": "https://github.com/jshttp/content-type/issues"
},
"homepage": "https://github.com/jshttp/content-type",
"_id": "content-type@1.0.1",
"_shasum": "a19d2247327dc038050ce622b7a154ec59c5e600",
"_from": "content-type@>=1.0.1 <1.1.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "a19d2247327dc038050ce622b7a154ec59c5e600",
"tarball": "http://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz"
}

View File

@ -1,4 +0,0 @@
support
test
examples
*.sock

View File

@ -1,38 +0,0 @@
1.0.6 / 2015-02-03
==================
* use `npm test` instead of `make test` to run tests
* clearer assertion messages when checking input
1.0.5 / 2014-09-05
==================
* add license to package.json
1.0.4 / 2014-06-25
==================
* corrected avoidance of timing attacks (thanks @tenbits!)
1.0.3 / 2014-01-28
==================
* [incorrect] fix for timing attacks
1.0.2 / 2014-01-28
==================
* fix missing repository warning
* fix typo in test
1.0.1 / 2013-04-15
==================
* Revert "Changed underlying HMAC algo. to sha512."
* Revert "Fix for timing attacks on MAC verification."
0.0.1 / 2010-01-03
==================
* Initial release

View File

@ -1,42 +0,0 @@
# cookie-signature
Sign and unsign cookies.
## Example
```js
var cookie = require('cookie-signature');
var val = cookie.sign('hello', 'tobiiscool');
val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');
var val = cookie.sign('hello', 'tobiiscool');
cookie.unsign(val, 'tobiiscool').should.equal('hello');
cookie.unsign(val, 'luna').should.be.false;
```
## License
(The MIT License)
Copyright (c) 2012 LearnBoost &lt;tj@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,51 +0,0 @@
/**
* Module dependencies.
*/
var crypto = require('crypto');
/**
* Sign the given `val` with `secret`.
*
* @param {String} val
* @param {String} secret
* @return {String}
* @api private
*/
exports.sign = function(val, secret){
if ('string' != typeof val) throw new TypeError("Cookie value must be provided as a string.");
if ('string' != typeof secret) throw new TypeError("Secret string must be provided.");
return val + '.' + crypto
.createHmac('sha256', secret)
.update(val)
.digest('base64')
.replace(/\=+$/, '');
};
/**
* Unsign and decode the given `val` with `secret`,
* returning `false` if the signature is invalid.
*
* @param {String} val
* @param {String} secret
* @return {String|Boolean}
* @api private
*/
exports.unsign = function(val, secret){
if ('string' != typeof val) throw new TypeError("Signed cookie string must be provided.");
if ('string' != typeof secret) throw new TypeError("Secret string must be provided.");
var str = val.slice(0, val.lastIndexOf('.'))
, mac = exports.sign(str, secret);
return sha1(mac) == sha1(val) ? str : false;
};
/**
* Private
*/
function sha1(str){
return crypto.createHash('sha1').update(str).digest('hex');
}

View File

@ -1,58 +0,0 @@
{
"name": "cookie-signature",
"version": "1.0.6",
"description": "Sign and unsign cookies",
"keywords": [
"cookie",
"sign",
"unsign"
],
"author": {
"name": "TJ Holowaychuk",
"email": "tj@learnboost.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/node-cookie-signature.git"
},
"dependencies": {},
"devDependencies": {
"mocha": "*",
"should": "*"
},
"scripts": {
"test": "mocha --require should --reporter spec"
},
"main": "index",
"gitHead": "391b56cf44d88c493491b7e3fc53208cfb976d2a",
"bugs": {
"url": "https://github.com/visionmedia/node-cookie-signature/issues"
},
"homepage": "https://github.com/visionmedia/node-cookie-signature",
"_id": "cookie-signature@1.0.6",
"_shasum": "e303a882b342cc3ee8ca513a79999734dab3ae2c",
"_from": "cookie-signature@1.0.6",
"_npmVersion": "2.3.0",
"_nodeVersion": "0.10.36",
"_npmUser": {
"name": "natevw",
"email": "natevw@yahoo.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "natevw",
"email": "natevw@yahoo.com"
}
],
"dist": {
"shasum": "e303a882b342cc3ee8ca513a79999734dab3ae2c",
"tarball": "http://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
}

View File

@ -1,23 +0,0 @@
(The MIT License)
Copyright (c) 2012-2014 Roman Shtylman <shtylman@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,64 +0,0 @@
# cookie
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
cookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers.
See [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.
## how?
```
npm install cookie
```
```javascript
var cookie = require('cookie');
var hdr = cookie.serialize('foo', 'bar');
// hdr = 'foo=bar';
var cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');
// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };
```
## more
The serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.
### path
> cookie path
### expires
> absolute expiration date for the cookie (Date object)
### maxAge
> relative max age of the cookie from when the client receives it (seconds)
### domain
> domain for the cookie
### secure
> true or false
### httpOnly
> true or false
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/cookie.svg
[npm-url]: https://npmjs.org/package/cookie
[node-version-image]: https://img.shields.io/node/v/cookie.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/cookie/master.svg
[travis-url]: https://travis-ci.org/jshttp/cookie
[coveralls-image]: https://img.shields.io/coveralls/jshttp/cookie/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
[downloads-image]: https://img.shields.io/npm/dm/cookie.svg
[downloads-url]: https://npmjs.org/package/cookie

View File

@ -1,116 +0,0 @@
/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* MIT Licensed
*/
/**
* Module exports.
* @public
*/
exports.parse = parse;
exports.serialize = serialize;
/**
* Module variables.
* @private
*/
var decode = decodeURIComponent;
var encode = encodeURIComponent;
/**
* Parse a cookie header.
*
* Parse the given cookie header string into an object
* The object has the various cookies as keys(names) => values
*
* @param {string} str
* @param {object} [options]
* @return {string}
* @public
*/
function parse(str, options) {
var obj = {}
var opt = options || {};
var pairs = str.split(/; */);
var dec = opt.decode || decode;
pairs.forEach(function(pair) {
var eq_idx = pair.indexOf('=')
// skip things that don't look like key=value
if (eq_idx < 0) {
return;
}
var key = pair.substr(0, eq_idx).trim()
var val = pair.substr(++eq_idx, pair.length).trim();
// quoted values
if ('"' == val[0]) {
val = val.slice(1, -1);
}
// only assign once
if (undefined == obj[key]) {
obj[key] = tryDecode(val, dec);
}
});
return obj;
}
/**
* Serialize data into a cookie header.
*
* Serialize the a name value pair into a cookie string suitable for
* http headers. An optional options object specified cookie parameters.
*
* serialize('foo', 'bar', { httpOnly: true })
* => "foo=bar; httpOnly"
*
* @param {string} name
* @param {string} val
* @param {object} [options]
* @return {string}
* @public
*/
function serialize(name, val, options) {
var opt = options || {};
var enc = opt.encode || encode;
var pairs = [name + '=' + enc(val)];
if (null != opt.maxAge) {
var maxAge = opt.maxAge - 0;
if (isNaN(maxAge)) throw new Error('maxAge should be a Number');
pairs.push('Max-Age=' + maxAge);
}
if (opt.domain) pairs.push('Domain=' + opt.domain);
if (opt.path) pairs.push('Path=' + opt.path);
if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString());
if (opt.httpOnly) pairs.push('HttpOnly');
if (opt.secure) pairs.push('Secure');
return pairs.join('; ');
}
/**
* Try decoding a string using a decoding function.
*
* @param {string} str
* @param {function} decode
* @private
*/
function tryDecode(str, decode) {
try {
return decode(str);
} catch (e) {
return str;
}
}

View File

@ -1,68 +0,0 @@
{
"name": "cookie",
"description": "cookie parsing and serialization",
"version": "0.1.3",
"author": {
"name": "Roman Shtylman",
"email": "shtylman@gmail.com"
},
"license": "MIT",
"keywords": [
"cookie",
"cookies"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/cookie"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "1.x.x"
},
"files": [
"LICENSE",
"README.md",
"index.js"
],
"engines": {
"node": "*"
},
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
},
"gitHead": "f46097723c16f920a7b9759e154c34792e1d1a3b",
"bugs": {
"url": "https://github.com/jshttp/cookie/issues"
},
"homepage": "https://github.com/jshttp/cookie",
"_id": "cookie@0.1.3",
"_shasum": "e734a5c1417fce472d5aef82c381cabb64d1a435",
"_from": "cookie@0.1.3",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "defunctzombie",
"email": "shtylman@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
}
],
"dist": {
"shasum": "e734a5c1417fce472d5aef82c381cabb64d1a435",
"tarball": "http://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
}

View File

@ -1,75 +0,0 @@
1.0.1 / 2015-04-07
==================
* Fix `TypeError`s when under `'use strict'` code
* Fix useless type name on auto-generated messages
* Support io.js 1.x
* Support Node.js 0.12
1.0.0 / 2014-09-17
==================
* No changes
0.4.5 / 2014-09-09
==================
* Improve call speed to functions using the function wrapper
* Support Node.js 0.6
0.4.4 / 2014-07-27
==================
* Work-around v8 generating empty stack traces
0.4.3 / 2014-07-26
==================
* Fix exception when global `Error.stackTraceLimit` is too low
0.4.2 / 2014-07-19
==================
* Correct call site for wrapped functions and properties
0.4.1 / 2014-07-19
==================
* Improve automatic message generation for function properties
0.4.0 / 2014-07-19
==================
* Add `TRACE_DEPRECATION` environment variable
* Remove non-standard grey color from color output
* Support `--no-deprecation` argument
* Support `--trace-deprecation` argument
* Support `deprecate.property(fn, prop, message)`
0.3.0 / 2014-06-16
==================
* Add `NO_DEPRECATION` environment variable
0.2.0 / 2014-06-15
==================
* Add `deprecate.property(obj, prop, message)`
* Remove `supports-color` dependency for node.js 0.8
0.1.0 / 2014-06-15
==================
* Add `deprecate.function(fn, message)`
* Add `process.on('deprecation', fn)` emitter
* Automatically generate message when omitted from `deprecate()`
0.0.1 / 2014-06-15
==================
* Fix warning for dynamic calls at singe call site
0.0.0 / 2014-06-15
==================
* Initial implementation

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,274 +0,0 @@
# depd
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-image]][node-url]
[![Linux Build][travis-image]][travis-url]
[![Windows Build][appveyor-image]][appveyor-url]
[![Coverage Status][coveralls-image]][coveralls-url]
[![Gratipay][gratipay-image]][gratipay-url]
Deprecate all the things
> With great modules comes great responsibility; mark things deprecated!
## Install
```sh
$ npm install depd
```
## API
```js
var deprecate = require('depd')('my-module')
```
This library allows you to display deprecation messages to your users.
This library goes above and beyond with deprecation warnings by
introspection of the call stack (but only the bits that it is interested
in).
Instead of just warning on the first invocation of a deprecated
function and never again, this module will warn on the first invocation
of a deprecated function per unique call site, making it ideal to alert
users of all deprecated uses across the code base, rather than just
whatever happens to execute first.
The deprecation warnings from this module also include the file and line
information for the call into the module that the deprecated function was
in.
**NOTE** this library has a similar interface to the `debug` module, and
this module uses the calling file to get the boundary for the call stacks,
so you should always create a new `deprecate` object in each file and not
within some central file.
### depd(namespace)
Create a new deprecate function that uses the given namespace name in the
messages and will display the call site prior to the stack entering the
file this function was called from. It is highly suggested you use the
name of your module as the namespace.
### deprecate(message)
Call this function from deprecated code to display a deprecation message.
This message will appear once per unique caller site. Caller site is the
first call site in the stack in a different file from the caller of this
function.
If the message is omitted, a message is generated for you based on the site
of the `deprecate()` call and will display the name of the function called,
similar to the name displayed in a stack trace.
### deprecate.function(fn, message)
Call this function to wrap a given function in a deprecation message on any
call to the function. An optional message can be supplied to provide a custom
message.
### deprecate.property(obj, prop, message)
Call this function to wrap a given property on object in a deprecation message
on any accessing or setting of the property. An optional message can be supplied
to provide a custom message.
The method must be called on the object where the property belongs (not
inherited from the prototype).
If the property is a data descriptor, it will be converted to an accessor
descriptor in order to display the deprecation message.
### process.on('deprecation', fn)
This module will allow easy capturing of deprecation errors by emitting the
errors as the type "deprecation" on the global `process`. If there are no
listeners for this type, the errors are written to STDERR as normal, but if
there are any listeners, nothing will be written to STDERR and instead only
emitted. From there, you can write the errors in a different format or to a
logging source.
The error represents the deprecation and is emitted only once with the same
rules as writing to STDERR. The error has the following properties:
- `message` - This is the message given by the library
- `name` - This is always `'DeprecationError'`
- `namespace` - This is the namespace the deprecation came from
- `stack` - This is the stack of the call to the deprecated thing
Example `error.stack` output:
```
DeprecationError: my-cool-module deprecated oldfunction
at Object.<anonymous> ([eval]-wrapper:6:22)
at Module._compile (module.js:456:26)
at evalScript (node.js:532:25)
at startup (node.js:80:7)
at node.js:902:3
```
### process.env.NO_DEPRECATION
As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
is provided as a quick solution to silencing deprecation warnings from being
output. The format of this is similar to that of `DEBUG`:
```sh
$ NO_DEPRECATION=my-module,othermod node app.js
```
This will suppress deprecations from being output for "my-module" and "othermod".
The value is a list of comma-separated namespaces. To suppress every warning
across all namespaces, use the value `*` for a namespace.
Providing the argument `--no-deprecation` to the `node` executable will suppress
all deprecations (only available in Node.js 0.8 or higher).
**NOTE** This will not suppress the deperecations given to any "deprecation"
event listeners, just the output to STDERR.
### process.env.TRACE_DEPRECATION
As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
is provided as a solution to getting more detailed location information in deprecation
warnings by including the entire stack trace. The format of this is the same as
`NO_DEPRECATION`:
```sh
$ TRACE_DEPRECATION=my-module,othermod node app.js
```
This will include stack traces for deprecations being output for "my-module" and
"othermod". The value is a list of comma-separated namespaces. To trace every
warning across all namespaces, use the value `*` for a namespace.
Providing the argument `--trace-deprecation` to the `node` executable will trace
all deprecations (only available in Node.js 0.8 or higher).
**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
## Display
![message](files/message.png)
When a user calls a function in your library that you mark deprecated, they
will see the following written to STDERR (in the given colors, similar colors
and layout to the `debug` module):
```
bright cyan bright yellow
| | reset cyan
| | | |
▼ ▼ ▼ ▼
my-cool-module deprecated oldfunction [eval]-wrapper:6:22
▲ ▲ ▲ ▲
| | | |
namespace | | location of mycoolmod.oldfunction() call
| deprecation message
the word "deprecated"
```
If the user redirects their STDERR to a file or somewhere that does not support
colors, they see (similar layout to the `debug` module):
```
Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
▲ ▲ ▲ ▲ ▲
| | | | |
timestamp of message namespace | | location of mycoolmod.oldfunction() call
| deprecation message
the word "deprecated"
```
## Examples
### Deprecating all calls to a function
This will display a deprecated message about "oldfunction" being deprecated
from "my-module" on STDERR.
```js
var deprecate = require('depd')('my-cool-module')
// message automatically derived from function name
// Object.oldfunction
exports.oldfunction = deprecate.function(function oldfunction() {
// all calls to function are deprecated
})
// specific message
exports.oldfunction = deprecate.function(function () {
// all calls to function are deprecated
}, 'oldfunction')
```
### Conditionally deprecating a function call
This will display a deprecated message about "weirdfunction" being deprecated
from "my-module" on STDERR when called with less than 2 arguments.
```js
var deprecate = require('depd')('my-cool-module')
exports.weirdfunction = function () {
if (arguments.length < 2) {
// calls with 0 or 1 args are deprecated
deprecate('weirdfunction args < 2')
}
}
```
When calling `deprecate` as a function, the warning is counted per call site
within your own module, so you can display different deprecations depending
on different situations and the users will still get all the warnings:
```js
var deprecate = require('depd')('my-cool-module')
exports.weirdfunction = function () {
if (arguments.length < 2) {
// calls with 0 or 1 args are deprecated
deprecate('weirdfunction args < 2')
} else if (typeof arguments[0] !== 'string') {
// calls with non-string first argument are deprecated
deprecate('weirdfunction non-string first arg')
}
}
```
### Deprecating property access
This will display a deprecated message about "oldprop" being deprecated
from "my-module" on STDERR when accessed. A deprecation will be displayed
when setting the value and when getting the value.
```js
var deprecate = require('depd')('my-cool-module')
exports.oldprop = 'something'
// message automatically derives from property name
deprecate.property(exports, 'oldprop')
// explicit message
deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
```
## License
[MIT](LICENSE)
[npm-version-image]: https://img.shields.io/npm/v/depd.svg
[npm-downloads-image]: https://img.shields.io/npm/dm/depd.svg
[npm-url]: https://npmjs.org/package/depd
[travis-image]: https://img.shields.io/travis/dougwilson/nodejs-depd/master.svg?label=linux
[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/nodejs-depd/master.svg?label=windows
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/nodejs-depd
[coveralls-image]: https://img.shields.io/coveralls/dougwilson/nodejs-depd/master.svg
[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master
[node-image]: https://img.shields.io/node/v/depd.svg
[node-url]: http://nodejs.org/download/
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
[gratipay-url]: https://www.gratipay.com/dougwilson/

View File

@ -1,529 +0,0 @@
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
*/
var callSiteToString = require('./lib/compat').callSiteToString
var EventEmitter = require('events').EventEmitter
var relative = require('path').relative
/**
* Module exports.
*/
module.exports = depd
/**
* Get the path to base files on.
*/
var basePath = process.cwd()
/**
* Get listener count on event emitter.
*/
/*istanbul ignore next*/
var eventListenerCount = EventEmitter.listenerCount
|| function (emitter, type) { return emitter.listeners(type).length }
/**
* Determine if namespace is contained in the string.
*/
function containsNamespace(str, namespace) {
var val = str.split(/[ ,]+/)
namespace = String(namespace).toLowerCase()
for (var i = 0 ; i < val.length; i++) {
if (!(str = val[i])) continue;
// namespace contained
if (str === '*' || str.toLowerCase() === namespace) {
return true
}
}
return false
}
/**
* Convert a data descriptor to accessor descriptor.
*/
function convertDataDescriptorToAccessor(obj, prop, message) {
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
var value = descriptor.value
descriptor.get = function getter() { return value }
if (descriptor.writable) {
descriptor.set = function setter(val) { return value = val }
}
delete descriptor.value
delete descriptor.writable
Object.defineProperty(obj, prop, descriptor)
return descriptor
}
/**
* Create arguments string to keep arity.
*/
function createArgumentsString(arity) {
var str = ''
for (var i = 0; i < arity; i++) {
str += ', arg' + i
}
return str.substr(2)
}
/**
* Create stack string from stack.
*/
function createStackString(stack) {
var str = this.name + ': ' + this.namespace
if (this.message) {
str += ' deprecated ' + this.message
}
for (var i = 0; i < stack.length; i++) {
str += '\n at ' + callSiteToString(stack[i])
}
return str
}
/**
* Create deprecate for namespace in caller.
*/
function depd(namespace) {
if (!namespace) {
throw new TypeError('argument namespace is required')
}
var stack = getStack()
var site = callSiteLocation(stack[1])
var file = site[0]
function deprecate(message) {
// call to self as log
log.call(deprecate, message)
}
deprecate._file = file
deprecate._ignored = isignored(namespace)
deprecate._namespace = namespace
deprecate._traced = istraced(namespace)
deprecate._warned = Object.create(null)
deprecate.function = wrapfunction
deprecate.property = wrapproperty
return deprecate
}
/**
* Determine if namespace is ignored.
*/
function isignored(namespace) {
/* istanbul ignore next: tested in a child processs */
if (process.noDeprecation) {
// --no-deprecation support
return true
}
var str = process.env.NO_DEPRECATION || ''
// namespace ignored
return containsNamespace(str, namespace)
}
/**
* Determine if namespace is traced.
*/
function istraced(namespace) {
/* istanbul ignore next: tested in a child processs */
if (process.traceDeprecation) {
// --trace-deprecation support
return true
}
var str = process.env.TRACE_DEPRECATION || ''
// namespace traced
return containsNamespace(str, namespace)
}
/**
* Display deprecation message.
*/
function log(message, site) {
var haslisteners = eventListenerCount(process, 'deprecation') !== 0
// abort early if no destination
if (!haslisteners && this._ignored) {
return
}
var caller
var callFile
var callSite
var i = 0
var seen = false
var stack = getStack()
var file = this._file
if (site) {
// provided site
callSite = callSiteLocation(stack[1])
callSite.name = site.name
file = callSite[0]
} else {
// get call site
i = 2
site = callSiteLocation(stack[i])
callSite = site
}
// get caller of deprecated thing in relation to file
for (; i < stack.length; i++) {
caller = callSiteLocation(stack[i])
callFile = caller[0]
if (callFile === file) {
seen = true
} else if (callFile === this._file) {
file = this._file
} else if (seen) {
break
}
}
var key = caller
? site.join(':') + '__' + caller.join(':')
: undefined
if (key !== undefined && key in this._warned) {
// already warned
return
}
this._warned[key] = true
// generate automatic message from call site
if (!message) {
message = callSite === site || !callSite.name
? defaultMessage(site)
: defaultMessage(callSite)
}
// emit deprecation if listeners exist
if (haslisteners) {
var err = DeprecationError(this._namespace, message, stack.slice(i))
process.emit('deprecation', err)
return
}
// format and write message
var format = process.stderr.isTTY
? formatColor
: formatPlain
var msg = format.call(this, message, caller, stack.slice(i))
process.stderr.write(msg + '\n', 'utf8')
return
}
/**
* Get call site location as array.
*/
function callSiteLocation(callSite) {
var file = callSite.getFileName() || '<anonymous>'
var line = callSite.getLineNumber()
var colm = callSite.getColumnNumber()
if (callSite.isEval()) {
file = callSite.getEvalOrigin() + ', ' + file
}
var site = [file, line, colm]
site.callSite = callSite
site.name = callSite.getFunctionName()
return site
}
/**
* Generate a default message from the site.
*/
function defaultMessage(site) {
var callSite = site.callSite
var funcName = site.name
// make useful anonymous name
if (!funcName) {
funcName = '<anonymous@' + formatLocation(site) + '>'
}
var context = callSite.getThis()
var typeName = context && callSite.getTypeName()
// ignore useless type name
if (typeName === 'Object') {
typeName = undefined
}
// make useful type name
if (typeName === 'Function') {
typeName = context.name || typeName
}
return typeName && callSite.getMethodName()
? typeName + '.' + funcName
: funcName
}
/**
* Format deprecation message without color.
*/
function formatPlain(msg, caller, stack) {
var timestamp = new Date().toUTCString()
var formatted = timestamp
+ ' ' + this._namespace
+ ' deprecated ' + msg
// add stack trace
if (this._traced) {
for (var i = 0; i < stack.length; i++) {
formatted += '\n at ' + callSiteToString(stack[i])
}
return formatted
}
if (caller) {
formatted += ' at ' + formatLocation(caller)
}
return formatted
}
/**
* Format deprecation message with color.
*/
function formatColor(msg, caller, stack) {
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' // bold cyan
+ ' \x1b[33;1mdeprecated\x1b[22;39m' // bold yellow
+ ' \x1b[0m' + msg + '\x1b[39m' // reset
// add stack trace
if (this._traced) {
for (var i = 0; i < stack.length; i++) {
formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan
}
return formatted
}
if (caller) {
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
}
return formatted
}
/**
* Format call site location.
*/
function formatLocation(callSite) {
return relative(basePath, callSite[0])
+ ':' + callSite[1]
+ ':' + callSite[2]
}
/**
* Get the stack as array of call sites.
*/
function getStack() {
var limit = Error.stackTraceLimit
var obj = {}
var prep = Error.prepareStackTrace
Error.prepareStackTrace = prepareObjectStackTrace
Error.stackTraceLimit = Math.max(10, limit)
// capture the stack
Error.captureStackTrace(obj)
// slice this function off the top
var stack = obj.stack.slice(1)
Error.prepareStackTrace = prep
Error.stackTraceLimit = limit
return stack
}
/**
* Capture call site stack from v8.
*/
function prepareObjectStackTrace(obj, stack) {
return stack
}
/**
* Return a wrapped function in a deprecation message.
*/
function wrapfunction(fn, message) {
if (typeof fn !== 'function') {
throw new TypeError('argument fn must be a function')
}
var args = createArgumentsString(fn.length)
var deprecate = this
var stack = getStack()
var site = callSiteLocation(stack[1])
site.name = fn.name
var deprecatedfn = eval('(function (' + args + ') {\n'
+ '"use strict"\n'
+ 'log.call(deprecate, message, site)\n'
+ 'return fn.apply(this, arguments)\n'
+ '})')
return deprecatedfn
}
/**
* Wrap property in a deprecation message.
*/
function wrapproperty(obj, prop, message) {
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
throw new TypeError('argument obj must be object')
}
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
if (!descriptor) {
throw new TypeError('must call property on owner object')
}
if (!descriptor.configurable) {
throw new TypeError('property must be configurable')
}
var deprecate = this
var stack = getStack()
var site = callSiteLocation(stack[1])
// set site name
site.name = prop
// convert data descriptor
if ('value' in descriptor) {
descriptor = convertDataDescriptorToAccessor(obj, prop, message)
}
var get = descriptor.get
var set = descriptor.set
// wrap getter
if (typeof get === 'function') {
descriptor.get = function getter() {
log.call(deprecate, message, site)
return get.apply(this, arguments)
}
}
// wrap setter
if (typeof set === 'function') {
descriptor.set = function setter() {
log.call(deprecate, message, site)
return set.apply(this, arguments)
}
}
Object.defineProperty(obj, prop, descriptor)
}
/**
* Create DeprecationError for deprecation
*/
function DeprecationError(namespace, message, stack) {
var error = new Error()
var stackString
Object.defineProperty(error, 'constructor', {
value: DeprecationError
})
Object.defineProperty(error, 'message', {
configurable: true,
enumerable: false,
value: message,
writable: true
})
Object.defineProperty(error, 'name', {
enumerable: false,
configurable: true,
value: 'DeprecationError',
writable: true
})
Object.defineProperty(error, 'namespace', {
configurable: true,
enumerable: false,
value: namespace,
writable: true
})
Object.defineProperty(error, 'stack', {
configurable: true,
enumerable: false,
get: function () {
if (stackString !== undefined) {
return stackString
}
// prepare stack trace
return stackString = createStackString.call(this, stack)
},
set: function setter(val) {
stackString = val
}
})
return error
}

View File

@ -1,33 +0,0 @@
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = bufferConcat
/**
* Concatenate an array of Buffers.
*/
function bufferConcat(bufs) {
var length = 0
for (var i = 0, len = bufs.length; i < len; i++) {
length += bufs[i].length
}
var buf = new Buffer(length)
var pos = 0
for (var i = 0, len = bufs.length; i < len; i++) {
bufs[i].copy(buf, pos)
pos += bufs[i].length
}
return buf
}

View File

@ -1,101 +0,0 @@
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = callSiteToString
/**
* Format a CallSite file location to a string.
*/
function callSiteFileLocation(callSite) {
var fileName
var fileLocation = ''
if (callSite.isNative()) {
fileLocation = 'native'
} else if (callSite.isEval()) {
fileName = callSite.getScriptNameOrSourceURL()
if (!fileName) {
fileLocation = callSite.getEvalOrigin()
}
} else {
fileName = callSite.getFileName()
}
if (fileName) {
fileLocation += fileName
var lineNumber = callSite.getLineNumber()
if (lineNumber != null) {
fileLocation += ':' + lineNumber
var columnNumber = callSite.getColumnNumber()
if (columnNumber) {
fileLocation += ':' + columnNumber
}
}
}
return fileLocation || 'unknown source'
}
/**
* Format a CallSite to a string.
*/
function callSiteToString(callSite) {
var addSuffix = true
var fileLocation = callSiteFileLocation(callSite)
var functionName = callSite.getFunctionName()
var isConstructor = callSite.isConstructor()
var isMethodCall = !(callSite.isToplevel() || isConstructor)
var line = ''
if (isMethodCall) {
var methodName = callSite.getMethodName()
var typeName = getConstructorName(callSite)
if (functionName) {
if (typeName && functionName.indexOf(typeName) !== 0) {
line += typeName + '.'
}
line += functionName
if (methodName && functionName.lastIndexOf('.' + methodName) !== functionName.length - methodName.length - 1) {
line += ' [as ' + methodName + ']'
}
} else {
line += typeName + '.' + (methodName || '<anonymous>')
}
} else if (isConstructor) {
line += 'new ' + (functionName || '<anonymous>')
} else if (functionName) {
line += functionName
} else {
addSuffix = false
line += fileLocation
}
if (addSuffix) {
line += ' (' + fileLocation + ')'
}
return line
}
/**
* Get constructor name of reviver.
*/
function getConstructorName(obj) {
var receiver = obj.receiver
return (receiver.constructor && receiver.constructor.name) || null
}

View File

@ -1,69 +0,0 @@
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
lazyProperty(module.exports, 'bufferConcat', function bufferConcat() {
return Buffer.concat || require('./buffer-concat')
})
lazyProperty(module.exports, 'callSiteToString', function callSiteToString() {
var limit = Error.stackTraceLimit
var obj = {}
var prep = Error.prepareStackTrace
function prepareObjectStackTrace(obj, stack) {
return stack
}
Error.prepareStackTrace = prepareObjectStackTrace
Error.stackTraceLimit = 2
// capture the stack
Error.captureStackTrace(obj)
// slice the stack
var stack = obj.stack.slice()
Error.prepareStackTrace = prep
Error.stackTraceLimit = limit
return stack[0].toString ? toString : require('./callsite-tostring')
})
/**
* Define a lazy property.
*/
function lazyProperty(obj, prop, getter) {
function get() {
var val = getter()
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: true,
value: val
})
return val
}
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: true,
get: get
})
}
/**
* Call toString() on the obj
*/
function toString(obj) {
return obj.toString()
}

View File

@ -1,65 +0,0 @@
{
"name": "depd",
"description": "Deprecate all the things",
"version": "1.0.1",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"keywords": [
"deprecate",
"deprecated"
],
"repository": {
"type": "git",
"url": "https://github.com/dougwilson/nodejs-depd"
},
"devDependencies": {
"benchmark": "1.0.0",
"beautify-benchmark": "0.2.4",
"istanbul": "0.3.5",
"mocha": "~1.21.5"
},
"files": [
"lib/",
"History.md",
"LICENSE",
"index.js",
"Readme.md"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"bench": "node benchmark/index.js",
"test": "mocha --reporter spec --bail test/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --no-exit test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/"
},
"gitHead": "769e0f8108463c35a6937a9d634ab19fee45100a",
"bugs": {
"url": "https://github.com/dougwilson/nodejs-depd/issues"
},
"homepage": "https://github.com/dougwilson/nodejs-depd",
"_id": "depd@1.0.1",
"_shasum": "80aec64c9d6d97e65cc2a9caa93c0aa6abf73aaa",
"_from": "depd@>=1.0.1 <1.1.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "80aec64c9d6d97e65cc2a9caa93c0aa6abf73aaa",
"tarball": "http://registry.npmjs.org/depd/-/depd-1.0.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz"
}

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2012-2013 TJ Holowaychuk
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,15 +0,0 @@
# escape-html
Escape HTML entities
## Example
```js
var escape = require('escape-html');
escape(str);
```
## License
MIT

View File

@ -1,29 +0,0 @@
/*!
* escape-html
* Copyright(c) 2012-2013 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module exports.
* @public
*/
module.exports = escapeHtml;
/**
* Escape special characters in the given string of html.
*
* @param {string} str The string to escape for inserting into HTML
* @return {string}
* @public
*/
function escapeHtml(html) {
return String(html)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}

View File

@ -1,50 +0,0 @@
{
"name": "escape-html",
"description": "Escape HTML entities",
"version": "1.0.2",
"license": "MIT",
"keywords": [
"escape",
"html",
"utility"
],
"repository": {
"type": "git",
"url": "https://github.com/component/escape-html"
},
"files": [
"LICENSE",
"Readme.md",
"index.js"
],
"gitHead": "2477a23ae56f75e0a5622a20b5b55da00de3a23b",
"bugs": {
"url": "https://github.com/component/escape-html/issues"
},
"homepage": "https://github.com/component/escape-html",
"_id": "escape-html@1.0.2",
"scripts": {},
"_shasum": "d77d32fa98e38c2f41ae85e9278e0e0e6ba1022c",
"_from": "escape-html@1.0.2",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "d77d32fa98e38c2f41ae85e9278e0e0e6ba1022c",
"tarball": "http://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz"
}

View File

@ -1,71 +0,0 @@
1.7.0 / 2015-06-08
==================
* Always include entity length in ETags for hash length extensions
* Generate non-Stats ETags using MD5 only (no longer CRC32)
* Improve stat performance by removing hashing
* Remove base64 padding in ETags to shorten
* Use MD5 instead of MD4 in weak ETags over 1KB
1.6.0 / 2015-05-10
==================
* Improve support for JXcore
* Remove requirement of `atime` in the stats object
* Support "fake" stats objects in environments without `fs`
1.5.1 / 2014-11-19
==================
* deps: crc@3.2.1
- Minor fixes
1.5.0 / 2014-10-14
==================
* Improve string performance
* Slightly improve speed for weak ETags over 1KB
1.4.0 / 2014-09-21
==================
* Support "fake" stats objects
* Support Node.js 0.6
1.3.1 / 2014-09-14
==================
* Use the (new and improved) `crc` for crc32
1.3.0 / 2014-08-29
==================
* Default strings to strong ETags
* Improve speed for weak ETags over 1KB
1.2.1 / 2014-08-29
==================
* Use the (much faster) `buffer-crc32` for crc32
1.2.0 / 2014-08-24
==================
* Add support for file stat objects
1.1.0 / 2014-08-24
==================
* Add fast-path for empty entity
* Add weak ETag generation
* Shrink size of generated ETags
1.0.1 / 2014-08-24
==================
* Fix behavior of string containing Unicode
1.0.0 / 2014-05-18
==================
* Initial release

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2014-2015 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,165 +0,0 @@
# etag
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Create simple ETags
## Installation
```sh
$ npm install etag
```
## API
```js
var etag = require('etag')
```
### etag(entity, [options])
Generate a strong ETag for the given entity. This should be the complete
body of the entity. Strings, `Buffer`s, and `fs.Stats` are accepted. By
default, a strong ETag is generated except for `fs.Stats`, which will
generate a weak ETag (this can be overwritten by `options.weak`).
```js
res.setHeader('ETag', etag(body))
```
#### Options
`etag` accepts these properties in the options object.
##### weak
Specifies if the generated ETag will include the weak validator mark (that
is, the leading `W/`). The actual entity tag is the same. The default value
is `false`, unless the `entity` is `fs.Stats`, in which case it is `true`.
## Testing
```sh
$ npm test
```
## Benchmark
```bash
$ npm run-script bench
> etag@1.6.0 bench nodejs-etag
> node benchmark/index.js
http_parser@1.0
node@0.10.33
v8@3.14.5.9
ares@1.9.0-DEV
uv@0.10.29
zlib@1.2.3
modules@11
openssl@1.0.1j
> node benchmark/body0-100b.js
100B body
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* buffer - strong x 289,198 ops/sec ±1.09% (190 runs sampled)
* buffer - weak x 287,838 ops/sec ±0.91% (189 runs sampled)
* string - strong x 284,586 ops/sec ±1.05% (192 runs sampled)
* string - weak x 287,439 ops/sec ±0.82% (192 runs sampled)
> node benchmark/body1-1kb.js
1KB body
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* buffer - strong x 212,423 ops/sec ±0.75% (193 runs sampled)
* buffer - weak x 211,871 ops/sec ±0.74% (194 runs sampled)
string - strong x 205,291 ops/sec ±0.86% (194 runs sampled)
string - weak x 208,463 ops/sec ±0.79% (192 runs sampled)
> node benchmark/body2-5kb.js
5KB body
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* buffer - strong x 92,901 ops/sec ±0.58% (195 runs sampled)
* buffer - weak x 93,045 ops/sec ±0.65% (192 runs sampled)
string - strong x 89,621 ops/sec ±0.68% (194 runs sampled)
string - weak x 90,070 ops/sec ±0.70% (196 runs sampled)
> node benchmark/body3-10kb.js
10KB body
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* buffer - strong x 54,220 ops/sec ±0.85% (192 runs sampled)
* buffer - weak x 54,069 ops/sec ±0.83% (191 runs sampled)
string - strong x 53,078 ops/sec ±0.53% (194 runs sampled)
string - weak x 53,849 ops/sec ±0.47% (197 runs sampled)
> node benchmark/body4-100kb.js
100KB body
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* buffer - strong x 6,673 ops/sec ±0.15% (197 runs sampled)
* buffer - weak x 6,716 ops/sec ±0.12% (198 runs sampled)
string - strong x 6,357 ops/sec ±0.14% (197 runs sampled)
string - weak x 6,344 ops/sec ±0.21% (197 runs sampled)
> node benchmark/stats.js
stats
1 test completed.
2 tests completed.
3 tests completed.
4 tests completed.
* real - strong x 1,671,989 ops/sec ±0.13% (197 runs sampled)
* real - weak x 1,681,297 ops/sec ±0.12% (198 runs sampled)
fake - strong x 927,063 ops/sec ±0.14% (198 runs sampled)
fake - weak x 914,461 ops/sec ±0.41% (191 runs sampled)
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/etag.svg
[npm-url]: https://npmjs.org/package/etag
[node-version-image]: https://img.shields.io/node/v/etag.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/etag/master.svg
[travis-url]: https://travis-ci.org/jshttp/etag
[coveralls-image]: https://img.shields.io/coveralls/jshttp/etag/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/etag?branch=master
[downloads-image]: https://img.shields.io/npm/dm/etag.svg
[downloads-url]: https://npmjs.org/package/etag

View File

@ -1,132 +0,0 @@
/*!
* etag
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = etag
/**
* Module dependencies.
* @private
*/
var crypto = require('crypto')
var Stats = require('fs').Stats
/**
* Module variables.
* @private
*/
var base64PadCharRegExp = /=+$/
var toString = Object.prototype.toString
/**
* Generate an entity tag.
*
* @param {Buffer|string} entity
* @return {string}
* @private
*/
function entitytag(entity) {
if (entity.length === 0) {
// fast-path empty
return '"0-1B2M2Y8AsgTpgAmY7PhCfg"'
}
// compute hash of entity
var hash = crypto
.createHash('md5')
.update(entity, 'utf8')
.digest('base64')
.replace(base64PadCharRegExp, '')
// compute length of entity
var len = typeof entity === 'string'
? Buffer.byteLength(entity, 'utf8')
: entity.length
return '"' + len.toString(16) + '-' + hash + '"'
}
/**
* Create a simple ETag.
*
* @param {string|Buffer|Stats} entity
* @param {object} [options]
* @param {boolean} [options.weak]
* @return {String}
* @public
*/
function etag(entity, options) {
if (entity == null) {
throw new TypeError('argument entity is required')
}
// support fs.Stats object
var isStats = isstats(entity)
var weak = options && typeof options.weak === 'boolean'
? options.weak
: isStats
// validate argument
if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
}
// generate entity tag
var tag = isStats
? stattag(entity)
: entitytag(entity)
return weak
? 'W/' + tag
: tag
}
/**
* Determine if object is a Stats object.
*
* @param {object} obj
* @return {boolean}
* @api private
*/
function isstats(obj) {
// genuine fs.Stats
if (typeof Stats === 'function' && obj instanceof Stats) {
return true
}
// quack quack
return obj && typeof obj === 'object'
&& 'ctime' in obj && toString.call(obj.ctime) === '[object Date]'
&& 'mtime' in obj && toString.call(obj.mtime) === '[object Date]'
&& 'ino' in obj && typeof obj.ino === 'number'
&& 'size' in obj && typeof obj.size === 'number'
}
/**
* Generate a tag for a stat.
*
* @param {object} stat
* @return {string}
* @private
*/
function stattag(stat) {
var mtime = stat.mtime.getTime().toString(16)
var size = stat.size.toString(16)
return '"' + size + '-' + mtime + '"'
}

View File

@ -1,72 +0,0 @@
{
"name": "etag",
"description": "Create simple ETags",
"version": "1.7.0",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "David Björklund",
"email": "david.bjorklund@gmail.com"
}
],
"license": "MIT",
"keywords": [
"etag",
"http",
"res"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/etag"
},
"devDependencies": {
"benchmark": "1.0.0",
"beautify-benchmark": "0.2.4",
"istanbul": "0.3.14",
"mocha": "~1.21.4",
"seedrandom": "2.3.11"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"bench": "node benchmark/index.js",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "a511f5c8c930fd9546dbd88acb080f96bc788cfc",
"bugs": {
"url": "https://github.com/jshttp/etag/issues"
},
"homepage": "https://github.com/jshttp/etag",
"_id": "etag@1.7.0",
"_shasum": "03d30b5f67dd6e632d2945d30d6652731a34d5d8",
"_from": "etag@>=1.7.0 <1.8.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "03d30b5f67dd6e632d2945d30d6652731a34d5d8",
"tarball": "http://registry.npmjs.org/etag/-/etag-1.7.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz"
}

View File

@ -1,38 +0,0 @@
0.3.0 / 2015-05-12
==================
* Add weak `ETag` matching support
0.2.4 / 2014-09-07
==================
* Support Node.js 0.6
0.2.3 / 2014-09-07
==================
* Move repository to jshttp
0.2.2 / 2014-02-19
==================
* Revert "Fix for blank page on Safari reload"
0.2.1 / 2014-01-29
==================
* Fix for blank page on Safari reload
0.2.0 / 2013-08-11
==================
* Return stale for `Cache-Control: no-cache`
0.1.0 / 2012-06-15
==================
* Add `If-None-Match: *` support
0.0.1 / 2012-06-10
==================
* Initial release

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,58 +0,0 @@
# fresh
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
HTTP response freshness testing
## Installation
```
$ npm install fresh
```
## API
```js
var fresh = require('fresh')
```
### fresh(req, res)
Check freshness of `req` and `res` headers.
When the cache is "fresh" __true__ is returned,
otherwise __false__ is returned to indicate that
the cache is now stale.
## Example
```js
var req = { 'if-none-match': 'tobi' };
var res = { 'etag': 'luna' };
fresh(req, res);
// => false
var req = { 'if-none-match': 'tobi' };
var res = { 'etag': 'tobi' };
fresh(req, res);
// => true
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/fresh.svg
[npm-url]: https://npmjs.org/package/fresh
[node-version-image]: https://img.shields.io/node/v/fresh.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/fresh/master.svg
[travis-url]: https://travis-ci.org/jshttp/fresh
[coveralls-image]: https://img.shields.io/coveralls/jshttp/fresh/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/fresh?branch=master
[downloads-image]: https://img.shields.io/npm/dm/fresh.svg
[downloads-url]: https://npmjs.org/package/fresh

View File

@ -1,57 +0,0 @@
/**
* Expose `fresh()`.
*/
module.exports = fresh;
/**
* Check freshness of `req` and `res` headers.
*
* When the cache is "fresh" __true__ is returned,
* otherwise __false__ is returned to indicate that
* the cache is now stale.
*
* @param {Object} req
* @param {Object} res
* @return {Boolean}
* @api public
*/
function fresh(req, res) {
// defaults
var etagMatches = true;
var notModified = true;
// fields
var modifiedSince = req['if-modified-since'];
var noneMatch = req['if-none-match'];
var lastModified = res['last-modified'];
var etag = res['etag'];
var cc = req['cache-control'];
// unconditional request
if (!modifiedSince && !noneMatch) return false;
// check for no-cache cache request directive
if (cc && cc.indexOf('no-cache') !== -1) return false;
// parse if-none-match
if (noneMatch) noneMatch = noneMatch.split(/ *, */);
// if-none-match
if (noneMatch) {
etagMatches = noneMatch.some(function (match) {
return match === '*' || match === etag || match === 'W/' + etag;
});
}
// if-modified-since
if (modifiedSince) {
modifiedSince = new Date(modifiedSince);
lastModified = new Date(lastModified);
notModified = lastModified <= modifiedSince;
}
return !! (etagMatches && notModified);
}

View File

@ -1,86 +0,0 @@
{
"name": "fresh",
"description": "HTTP response freshness testing",
"version": "0.3.0",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
}
],
"license": "MIT",
"keywords": [
"fresh",
"http",
"conditional",
"cache"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/fresh"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "1.21.5"
},
"files": [
"HISTORY.md",
"LICENSE",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "14616c9748368ca08cd6a955dd88ab659b778634",
"bugs": {
"url": "https://github.com/jshttp/fresh/issues"
},
"homepage": "https://github.com/jshttp/fresh",
"_id": "fresh@0.3.0",
"_shasum": "651f838e22424e7566de161d8358caa199f83d4f",
"_from": "fresh@0.3.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "jonathanong",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
}
],
"dist": {
"shasum": "651f838e22424e7566de161d8358caa199f83d4f",
"tarball": "http://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz"
}

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2013 Jonathan Ong <me@jongleberry.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,34 +0,0 @@
# Merge Descriptors
Merge objects using descriptors.
```js
var thing = {
get name() {
return 'jon'
}
}
var animal = {
}
merge(animal, thing)
animal.name === 'jon'
```
## API
### merge(destination, source)
Redefines `destination`'s descriptors with `source`'s.
### merge(destination, source, false)
Defines `source`'s descriptors on `destination` if `destination` does not have
a descriptor by the same name.
## License
[MIT](LICENSE)

View File

@ -1,57 +0,0 @@
/*!
* merge-descriptors
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/**
* Module exports.
* @public
*/
module.exports = merge
/**
* Module variables.
* @private
*/
var hasOwnProperty = Object.prototype.hasOwnProperty
/**
* Merge the property descriptors of `src` into `dest`
*
* @param {object} dest Object to add descriptors to
* @param {object} src Object to clone descriptors from
* @param {boolean} [redefine=true] Redefine `dest` properties with `src` properties
* @returns {object} Reference to dest
* @public
*/
function merge(dest, src, redefine) {
if (!dest) {
throw new TypeError('argument dest is required')
}
if (!src) {
throw new TypeError('argument src is required')
}
if (redefine === undefined) {
// Default to true
redefine = true
}
Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName(name) {
if (!redefine && hasOwnProperty.call(dest, name)) {
// Skip desriptor
return
}
// Copy descriptor
var descriptor = Object.getOwnPropertyDescriptor(src, name)
Object.defineProperty(dest, name, descriptor)
})
return dest
}

View File

@ -1,124 +0,0 @@
{
"name": "merge-descriptors",
"description": "Merge objects using descriptors",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/component/merge-descriptors.git"
},
"bugs": {
"url": "https://github.com/component/merge-descriptors/issues"
},
"files": [
"LICENSE",
"README.md",
"index.js"
],
"gitHead": "81d7a3c14099884c391bd237d7d8edf23c6d6f18",
"homepage": "https://github.com/component/merge-descriptors",
"_id": "merge-descriptors@1.0.0",
"scripts": {},
"_shasum": "2169cf7538e1b0cc87fb88e1502d8474bbf79864",
"_from": "merge-descriptors@1.0.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "tootallnate",
"email": "nathan@tootallnate.net"
},
{
"name": "juliangruber",
"email": "julian@juliangruber.com"
},
{
"name": "yields",
"email": "yields@icloud.com"
},
{
"name": "ianstormtaylor",
"email": "ian@ianstormtaylor.com"
},
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "timoxley",
"email": "secoif@gmail.com"
},
{
"name": "mattmueller",
"email": "mattmuelle@gmail.com"
},
{
"name": "jonathanong",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "queckezz",
"email": "fabian.eichenberger@gmail.com"
},
{
"name": "anthonyshort",
"email": "antshort@gmail.com"
},
{
"name": "dominicbarnes",
"email": "dominic@dbarnes.info"
},
{
"name": "clintwood",
"email": "clint@anotherway.co.za"
},
{
"name": "thehydroimpulse",
"email": "dnfagnan@gmail.com"
},
{
"name": "stephenmathieson",
"email": "me@stephenmathieson.com"
},
{
"name": "trevorgerhardt",
"email": "trevorgerhardt@gmail.com"
},
{
"name": "timaschew",
"email": "timaschew@gmail.com"
},
{
"name": "hughsk",
"email": "hughskennedy@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "2169cf7538e1b0cc87fb88e1502d8474bbf79864",
"tarball": "http://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz"
}

View File

@ -1,24 +0,0 @@
1.1.1 / 2014-12-30
==================
* Improve `browserify` support
1.1.0 / 2014-07-05
==================
* Add `CONNECT` method
1.0.1 / 2014-06-02
==================
* Fix module to work with harmony transform
1.0.0 / 2014-05-08
==================
* Add `PURGE` method
0.1.0 / 2013-10-28
==================
* Add `http.METHODS` support

View File

@ -1,23 +0,0 @@
(The MIT License)
Copyright (c) 2013-2014 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,41 +0,0 @@
# Methods
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
HTTP verbs that node core's parser supports.
## Install
```bash
$ npm install methods
```
## API
```js
var methods = require('methods')
```
### methods
This is an array of lower-case method names that Node.js supports.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/methods.svg?style=flat
[npm-url]: https://npmjs.org/package/methods
[node-version-image]: https://img.shields.io/node/v/methods.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/methods.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/methods
[coveralls-image]: https://img.shields.io/coveralls/jshttp/methods.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/methods?branch=master
[downloads-image]: https://img.shields.io/npm/dm/methods.svg?style=flat
[downloads-url]: https://npmjs.org/package/methods

View File

@ -1,42 +0,0 @@
var http = require('http');
/* istanbul ignore next: implementation differs on version */
if (http.METHODS) {
module.exports = http.METHODS.map(function(method){
return method.toLowerCase();
});
} else {
module.exports = [
'get',
'post',
'put',
'head',
'delete',
'options',
'trace',
'copy',
'lock',
'mkcol',
'move',
'purge',
'propfind',
'proppatch',
'unlock',
'report',
'mkactivity',
'checkout',
'merge',
'm-search',
'notify',
'subscribe',
'unsubscribe',
'patch',
'search',
'connect'
];
}

View File

@ -1,87 +0,0 @@
{
"name": "methods",
"description": "HTTP methods that node supports",
"version": "1.1.1",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
{
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/jshttp/methods"
},
"devDependencies": {
"istanbul": "0.3",
"mocha": "1"
},
"files": [
"index.js",
"HISTORY.md",
"LICENSE"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot"
},
"browser": {
"http": false
},
"keywords": [
"http",
"methods"
],
"gitHead": "6293c6b27c5fb963acf67a347af80ad2ebd7247f",
"bugs": {
"url": "https://github.com/jshttp/methods/issues"
},
"homepage": "https://github.com/jshttp/methods",
"_id": "methods@1.1.1",
"_shasum": "17ea6366066d00c58e375b8ec7dfd0453c89822a",
"_from": "methods@>=1.1.1 <1.2.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "jonathanong",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "17ea6366066d00c58e375b8ec7dfd0453c89822a",
"tarball": "http://registry.npmjs.org/methods/-/methods-1.1.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/methods/-/methods-1.1.1.tgz"
}

View File

@ -1,4 +0,0 @@
benchmark/
coverage/
test/
.travis.yml

View File

@ -1,42 +0,0 @@
1.3.0 / 2014-08-09
==================
* Add `parseurl.original` for parsing `req.originalUrl` with fallback
* Return `undefined` if `req.url` is `undefined`
1.2.0 / 2014-07-21
==================
* Cache URLs based on original value
* Remove no-longer-needed URL mis-parse work-around
* Simplify the "fast-path" `RegExp`
1.1.3 / 2014-07-08
==================
* Fix typo
1.1.2 / 2014-07-08
==================
* Seriously fix Node.js 0.8 compatibility
1.1.1 / 2014-07-08
==================
* Fix Node.js 0.8 compatibility
1.1.0 / 2014-07-08
==================
* Incorporate URL href-only parse fast-path
1.0.1 / 2014-03-08
==================
* Add missing `require`
1.0.0 / 2014-03-08
==================
* Genesis from `connect`

View File

@ -1,24 +0,0 @@
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Copyright (c) 2014 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,107 +0,0 @@
# parseurl
[![NPM version](https://badge.fury.io/js/parseurl.svg)](http://badge.fury.io/js/parseurl)
[![Build Status](https://travis-ci.org/expressjs/parseurl.svg?branch=master)](https://travis-ci.org/expressjs/parseurl)
[![Coverage Status](https://img.shields.io/coveralls/expressjs/parseurl.svg?branch=master)](https://coveralls.io/r/expressjs/parseurl)
Parse a URL with memoization.
## Install
```bash
$ npm install parseurl
```
## API
```js
var parseurl = require('parseurl')
```
### parseurl(req)
Parse the URL of the given request object (looks at the `req.url` property)
and return the result. The result is the same as `url.parse` in Node.js core.
Calling this function multiple times on the same `req` where `req.url` does
not change will return a cached parsed object, rather than parsing again.
### parseurl.original(req)
Parse the original URL of the given request object and return the result.
This works by trying to parse `req.originalUrl` if it is a string, otherwise
parses `req.url`. The result is the same as `url.parse` in Node.js core.
Calling this function multiple times on the same `req` where `req.originalUrl`
does not change will return a cached parsed object, rather than parsing again.
## Benchmark
```bash
$ npm run-script bench
> parseurl@1.3.0 bench nodejs-parseurl
> node benchmark/index.js
> node benchmark/fullurl.js
Parsing URL "http://localhost:8888/foo/bar?user=tj&pet=fluffy"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 1,290,780 ops/sec ±0.46% (195 runs sampled)
nativeurl x 56,401 ops/sec ±0.22% (196 runs sampled)
parseurl x 55,231 ops/sec ±0.22% (194 runs sampled)
> node benchmark/pathquery.js
Parsing URL "/foo/bar?user=tj&pet=fluffy"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 1,986,668 ops/sec ±0.27% (190 runs sampled)
nativeurl x 98,740 ops/sec ±0.21% (195 runs sampled)
parseurl x 2,628,171 ops/sec ±0.36% (195 runs sampled)
> node benchmark/samerequest.js
Parsing URL "/foo/bar?user=tj&pet=fluffy" on same request object
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 2,184,468 ops/sec ±0.40% (194 runs sampled)
nativeurl x 99,437 ops/sec ±0.71% (194 runs sampled)
parseurl x 10,498,005 ops/sec ±0.61% (186 runs sampled)
> node benchmark/simplepath.js
Parsing URL "/foo/bar"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 4,535,825 ops/sec ±0.27% (191 runs sampled)
nativeurl x 98,769 ops/sec ±0.54% (191 runs sampled)
parseurl x 4,164,865 ops/sec ±0.34% (192 runs sampled)
> node benchmark/slash.js
Parsing URL "/"
1 test completed.
2 tests completed.
3 tests completed.
fasturl x 4,908,405 ops/sec ±0.42% (191 runs sampled)
nativeurl x 100,945 ops/sec ±0.59% (188 runs sampled)
parseurl x 4,333,208 ops/sec ±0.27% (194 runs sampled)
```
## License
[MIT](LICENSE)

View File

@ -1,136 +0,0 @@
/*!
* parseurl
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
*/
var url = require('url')
var parse = url.parse
var Url = url.Url
/**
* Pattern for a simple path case.
* See: https://github.com/joyent/node/pull/7878
*/
var simplePathRegExp = /^(\/\/?(?!\/)[^\?#\s]*)(\?[^#\s]*)?$/
/**
* Exports.
*/
module.exports = parseurl
module.exports.original = originalurl
/**
* Parse the `req` url with memoization.
*
* @param {ServerRequest} req
* @return {Object}
* @api public
*/
function parseurl(req) {
var url = req.url
if (url === undefined) {
// URL is undefined
return undefined
}
var parsed = req._parsedUrl
if (fresh(url, parsed)) {
// Return cached URL parse
return parsed
}
// Parse the URL
parsed = fastparse(url)
parsed._raw = url
return req._parsedUrl = parsed
};
/**
* Parse the `req` original url with fallback and memoization.
*
* @param {ServerRequest} req
* @return {Object}
* @api public
*/
function originalurl(req) {
var url = req.originalUrl
if (typeof url !== 'string') {
// Fallback
return parseurl(req)
}
var parsed = req._parsedOriginalUrl
if (fresh(url, parsed)) {
// Return cached URL parse
return parsed
}
// Parse the URL
parsed = fastparse(url)
parsed._raw = url
return req._parsedOriginalUrl = parsed
};
/**
* Parse the `str` url with fast-path short-cut.
*
* @param {string} str
* @return {Object}
* @api private
*/
function fastparse(str) {
// Try fast path regexp
// See: https://github.com/joyent/node/pull/7878
var simplePath = typeof str === 'string' && simplePathRegExp.exec(str)
// Construct simple URL
if (simplePath) {
var pathname = simplePath[1]
var search = simplePath[2] || null
var url = Url !== undefined
? new Url()
: {}
url.path = str
url.href = str
url.pathname = pathname
url.search = search
url.query = search && search.substr(1)
return url
}
return parse(str)
}
/**
* Determine if parsed is still fresh for url.
*
* @param {string} url
* @param {object} parsedUrl
* @return {boolean}
* @api private
*/
function fresh(url, parsedUrl) {
return typeof parsedUrl === 'object'
&& parsedUrl !== null
&& (Url === undefined || parsedUrl instanceof Url)
&& parsedUrl._raw === url
}

View File

@ -1,79 +0,0 @@
{
"name": "parseurl",
"description": "parse a url with memoization",
"version": "1.3.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/expressjs/parseurl"
},
"license": "MIT",
"devDependencies": {
"benchmark": "1.0.0",
"beautify-benchmark": "0.2.4",
"fast-url-parser": "~1.0.0",
"istanbul": "0.3.0",
"mocha": "~1.21.4"
},
"scripts": {
"bench": "node benchmark/index.js",
"test": "mocha --check-leaks --bail --reporter spec test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec test/"
},
"gitHead": "03b7ccca240e2bef5df6c25797e99175d28fb2cb",
"bugs": {
"url": "https://github.com/expressjs/parseurl/issues"
},
"homepage": "https://github.com/expressjs/parseurl",
"_id": "parseurl@1.3.0",
"_shasum": "b58046db4223e145afa76009e61bac87cc2281b3",
"_from": "parseurl@>=1.3.0 <1.4.0",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "shtylman",
"email": "shtylman@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "mscdex",
"email": "mscdex@mscdex.net"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
}
],
"dist": {
"shasum": "b58046db4223e145afa76009e61bac87cc2281b3",
"tarball": "http://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz"
}

View File

@ -1,66 +0,0 @@
1.0.8 / 2015-05-10
==================
* deps: ipaddr.js@1.0.1
1.0.7 / 2015-03-16
==================
* deps: ipaddr.js@0.1.9
- Fix OOM on certain inputs to `isValid`
1.0.6 / 2015-02-01
==================
* deps: ipaddr.js@0.1.8
1.0.5 / 2015-01-08
==================
* deps: ipaddr.js@0.1.6
1.0.4 / 2014-11-23
==================
* deps: ipaddr.js@0.1.5
- Fix edge cases with `isValid`
1.0.3 / 2014-09-21
==================
* Use `forwarded` npm module
1.0.2 / 2014-09-18
==================
* Fix a global leak when multiple subnets are trusted
* Support Node.js 0.6
* deps: ipaddr.js@0.1.3
1.0.1 / 2014-06-03
==================
* Fix links in npm package
1.0.0 / 2014-05-08
==================
* Add `trust` argument to determine proxy trust on
* Accepts custom function
* Accepts IPv4/IPv6 address(es)
* Accepts subnets
* Accepts pre-defined names
* Add optional `trust` argument to `proxyaddr.all` to
stop at first untrusted
* Add `proxyaddr.compile` to pre-compile `trust` function
to make subsequent calls faster
0.0.1 / 2014-05-04
==================
* Fix bad npm publish
0.0.0 / 2014-05-04
==================
* Initial release

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,137 +0,0 @@
# proxy-addr
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Determine address of proxied request
## Install
```sh
$ npm install proxy-addr
```
## API
```js
var proxyaddr = require('proxy-addr')
```
### proxyaddr(req, trust)
Return the address of the request, using the given `trust` parameter.
The `trust` argument is a function that returns `true` if you trust
the address, `false` if you don't. The closest untrusted address is
returned.
```js
proxyaddr(req, function(addr){ return addr === '127.0.0.1' })
proxyaddr(req, function(addr, i){ return i < 1 })
```
The `trust` arugment may also be a single IP address string or an
array of trusted addresses, as plain IP addresses, CIDR-formatted
strings, or IP/netmask strings.
```js
proxyaddr(req, '127.0.0.1')
proxyaddr(req, ['127.0.0.0/8', '10.0.0.0/8'])
proxyaddr(req, ['127.0.0.0/255.0.0.0', '192.168.0.0/255.255.0.0'])
```
This module also supports IPv6. Your IPv6 addresses will be normalized
automatically (i.e. `fe80::00ed:1` equals `fe80:0:0:0:0:0:ed:1`).
```js
proxyaddr(req, '::1')
proxyaddr(req, ['::1/128', 'fe80::/10'])
proxyaddr(req, ['fe80::/ffc0::'])
```
This module will automatically work with IPv4-mapped IPv6 addresses
as well to support node.js in IPv6-only mode. This means that you do
not have to specify both `::ffff:a00:1` and `10.0.0.1`.
As a convenience, this module also takes certain pre-defined names
in addition to IP addresses, which expand into IP addresses:
```js
proxyaddr(req, 'loopback')
proxyaddr(req, ['loopback', 'fc00:ac:1ab5:fff::1/64'])
```
* `loopback`: IPv4 and IPv6 loopback addresses (like `::1` and
`127.0.0.1`).
* `linklocal`: IPv4 and IPv6 link-local addresses (like
`fe80::1:1:1:1` and `169.254.0.1`).
* `uniquelocal`: IPv4 private addresses and IPv6 unique-local
addresses (like `fc00:ac:1ab5:fff::1` and `192.168.0.1`).
When `trust` is specified as a function, it will be called for each
address to determine if it is a trusted address. The function is
given two arguments: `addr` and `i`, where `addr` is a string of
the address to check and `i` is a number that represents the distance
from the socket address.
### proxyaddr.all(req, [trust])
Return all the addresses of the request, optionally stopping at the
first untrusted. This array is ordered from closest to furthest
(i.e. `arr[0] === req.connection.remoteAddress`).
```js
proxyaddr.all(req)
```
The optional `trust` argument takes the same arguments as `trust`
does in `proxyaddr(req, trust)`.
```js
proxyaddr.all(req, 'loopback')
```
### proxyaddr.compile(val)
Compiles argument `val` into a `trust` function. This function takes
the same arguments as `trust` does in `proxyaddr(req, trust)` and
returns a function suitable for `proxyaddr(req, trust)`.
```js
var trust = proxyaddr.compile('localhost')
var addr = proxyaddr(req, trust)
```
This function is meant to be optimized for use against every request.
It is recommend to compile a trust function up-front for the trusted
configuration and pass that to `proxyaddr(req, trust)` for each request.
## Testing
```sh
$ npm test
```
## Benchmarks
```sh
$ npm run-script bench
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/proxy-addr.svg
[npm-url]: https://npmjs.org/package/proxy-addr
[node-version-image]: https://img.shields.io/node/v/proxy-addr.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/proxy-addr/master.svg
[travis-url]: https://travis-ci.org/jshttp/proxy-addr
[coveralls-image]: https://img.shields.io/coveralls/jshttp/proxy-addr/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/proxy-addr?branch=master
[downloads-image]: https://img.shields.io/npm/dm/proxy-addr.svg
[downloads-url]: https://npmjs.org/package/proxy-addr

View File

@ -1,345 +0,0 @@
/*!
* proxy-addr
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = proxyaddr;
module.exports.all = alladdrs;
module.exports.compile = compile;
/**
* Module dependencies.
*/
var forwarded = require('forwarded');
var ipaddr = require('ipaddr.js');
/**
* Variables.
*/
var digitre = /^[0-9]+$/;
var isip = ipaddr.isValid;
var parseip = ipaddr.parse;
/**
* Pre-defined IP ranges.
*/
var ipranges = {
linklocal: ['169.254.0.0/16', 'fe80::/10'],
loopback: ['127.0.0.1/8', '::1/128'],
uniquelocal: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']
};
/**
* Get all addresses in the request, optionally stopping
* at the first untrusted.
*
* @param {Object} request
* @param {Function|Array|String} [trust]
* @api public
*/
function alladdrs(req, trust) {
// get addresses
var addrs = forwarded(req);
if (!trust) {
// Return all addresses
return addrs;
}
if (typeof trust !== 'function') {
trust = compile(trust);
}
for (var i = 0; i < addrs.length - 1; i++) {
if (trust(addrs[i], i)) continue;
addrs.length = i + 1;
}
return addrs;
}
/**
* Compile argument into trust function.
*
* @param {Array|String} val
* @api private
*/
function compile(val) {
if (!val) {
throw new TypeError('argument is required');
}
var trust = typeof val === 'string'
? [val]
: val;
if (!Array.isArray(trust)) {
throw new TypeError('unsupported trust argument');
}
for (var i = 0; i < trust.length; i++) {
val = trust[i];
if (!ipranges.hasOwnProperty(val)) {
continue;
}
// Splice in pre-defined range
val = ipranges[val];
trust.splice.apply(trust, [i, 1].concat(val));
i += val.length - 1;
}
return compileTrust(compileRangeSubnets(trust));
}
/**
* Compile `arr` elements into range subnets.
*
* @param {Array} arr
* @api private
*/
function compileRangeSubnets(arr) {
var rangeSubnets = new Array(arr.length);
for (var i = 0; i < arr.length; i++) {
rangeSubnets[i] = parseipNotation(arr[i]);
}
return rangeSubnets;
}
/**
* Compile range subnet array into trust function.
*
* @param {Array} rangeSubnets
* @api private
*/
function compileTrust(rangeSubnets) {
// Return optimized function based on length
var len = rangeSubnets.length;
return len === 0
? trustNone
: len === 1
? trustSingle(rangeSubnets[0])
: trustMulti(rangeSubnets);
}
/**
* Parse IP notation string into range subnet.
*
* @param {String} note
* @api private
*/
function parseipNotation(note) {
var ip;
var kind;
var max;
var pos = note.lastIndexOf('/');
var range;
ip = pos !== -1
? note.substring(0, pos)
: note;
if (!isip(ip)) {
throw new TypeError('invalid IP address: ' + ip);
}
ip = parseip(ip);
kind = ip.kind();
max = kind === 'ipv6'
? 128
: 32;
range = pos !== -1
? note.substring(pos + 1, note.length)
: max;
if (typeof range !== 'number') {
range = digitre.test(range)
? parseInt(range, 10)
: isip(range)
? parseNetmask(range)
: 0;
}
if (ip.kind() === 'ipv6' && ip.isIPv4MappedAddress()) {
// Store as IPv4
ip = ip.toIPv4Address();
range = range <= max
? range - 96
: range;
}
if (range <= 0 || range > max) {
throw new TypeError('invalid range on address: ' + note);
}
return [ip, range];
}
/**
* Parse netmask string into CIDR range.
*
* @param {String} note
* @api private
*/
function parseNetmask(netmask) {
var ip = parseip(netmask);
var parts;
var size;
switch (ip.kind()) {
case 'ipv4':
parts = ip.octets;
size = 8;
break;
case 'ipv6':
parts = ip.parts;
size = 16;
break;
}
var max = Math.pow(2, size) - 1;
var part;
var range = 0;
for (var i = 0; i < parts.length; i++) {
part = parts[i] & max;
if (part === max) {
range += size;
continue;
}
while (part) {
part = (part << 1) & max;
range += 1;
}
break;
}
return range;
}
/**
* Determine address of proxied request.
*
* @param {Object} request
* @param {Function|Array|String} trust
* @api public
*/
function proxyaddr(req, trust) {
if (!req) {
throw new TypeError('req argument is required');
}
if (!trust) {
throw new TypeError('trust argument is required');
}
var addrs = alladdrs(req, trust);
var addr = addrs[addrs.length - 1];
return addr;
}
/**
* Static trust function to trust nothing.
*
* @api private
*/
function trustNone() {
return false;
}
/**
* Compile trust function for multiple subnets.
*
* @param {Array} subnets
* @api private
*/
function trustMulti(subnets) {
return function trust(addr) {
if (!isip(addr)) return false;
var ip = parseip(addr);
var ipv4;
var kind = ip.kind();
var subnet;
var subnetip;
var subnetkind;
var subnetrange;
var trusted;
for (var i = 0; i < subnets.length; i++) {
subnet = subnets[i];
subnetip = subnet[0];
subnetkind = subnetip.kind();
subnetrange = subnet[1];
trusted = ip;
if (kind !== subnetkind) {
if (kind !== 'ipv6' || subnetkind !== 'ipv4' || !ip.isIPv4MappedAddress()) {
continue;
}
// Store addr as IPv4
ipv4 = ipv4 || ip.toIPv4Address();
trusted = ipv4;
}
if (trusted.match(subnetip, subnetrange)) return true;
}
return false;
};
}
/**
* Compile trust function for single subnet.
*
* @param {Object} subnet
* @api private
*/
function trustSingle(subnet) {
var subnetip = subnet[0];
var subnetkind = subnetip.kind();
var subnetisipv4 = subnetkind === 'ipv4';
var subnetrange = subnet[1];
return function trust(addr) {
if (!isip(addr)) return false;
var ip = parseip(addr);
var kind = ip.kind();
return kind === subnetkind
? ip.match(subnetip, subnetrange)
: subnetisipv4 && kind === 'ipv6' && ip.isIPv4MappedAddress()
? ip.toIPv4Address().match(subnetip, subnetrange)
: false;
};
}

View File

@ -1,4 +0,0 @@
0.1.0 / 2014-09-21
==================
* Initial release

View File

@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,53 +0,0 @@
# forwarded
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Parse HTTP X-Forwarded-For header
## Installation
```sh
$ npm install forwarded
```
## API
```js
var forwarded = require('forwarded')
```
### forwarded(req)
```js
var addresses = forwarded(req)
```
Parse the `X-Forwarded-For` header from the request. Returns an array
of the addresses, including the socket address for the `req`. In reverse
order (i.e. index `0` is the socket address and the last index is the
furthest address, typically the end-user).
## Testing
```sh
$ npm test
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/forwarded.svg?style=flat
[npm-url]: https://npmjs.org/package/forwarded
[node-version-image]: https://img.shields.io/node/v/forwarded.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/forwarded.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/forwarded
[coveralls-image]: https://img.shields.io/coveralls/jshttp/forwarded.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/forwarded?branch=master
[downloads-image]: https://img.shields.io/npm/dm/forwarded.svg?style=flat
[downloads-url]: https://npmjs.org/package/forwarded

View File

@ -1,35 +0,0 @@
/*!
* forwarded
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = forwarded
/**
* Get all addresses in the request, using the `X-Forwarded-For` header.
*
* @param {Object} req
* @api public
*/
function forwarded(req) {
if (!req) {
throw new TypeError('argument req is required')
}
// simple header parsing
var proxyAddrs = (req.headers['x-forwarded-for'] || '')
.split(/ *, */)
.filter(Boolean)
.reverse()
var socketAddr = req.connection.remoteAddress
var addrs = [socketAddr].concat(proxyAddrs)
// return all addresses
return addrs
}

View File

@ -1,64 +0,0 @@
{
"name": "forwarded",
"description": "Parse HTTP X-Forwarded-For header",
"version": "0.1.0",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"license": "MIT",
"keywords": [
"x-forwarded-for",
"http",
"req"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/forwarded"
},
"devDependencies": {
"istanbul": "0.3.2",
"mocha": "~1.21.4"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "e9a9faeb3cfaadf40eb57d144fff26bca9b818e8",
"bugs": {
"url": "https://github.com/jshttp/forwarded/issues"
},
"homepage": "https://github.com/jshttp/forwarded",
"_id": "forwarded@0.1.0",
"_shasum": "19ef9874c4ae1c297bcf078fde63a09b66a84363",
"_from": "forwarded@>=0.1.0 <0.2.0",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "19ef9874c4ae1c297bcf078fde63a09b66a84363",
"tarball": "http://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz"
}

View File

@ -1,2 +0,0 @@
.idea
node_modules

View File

@ -1,18 +0,0 @@
fs = require 'fs'
CoffeeScript = require 'coffee-script'
nodeunit = require 'nodeunit'
UglifyJS = require 'uglify-js'
task 'build', 'build the JavaScript files from CoffeeScript source', build = (cb) ->
source = fs.readFileSync 'src/ipaddr.coffee'
fs.writeFileSync 'lib/ipaddr.js', CoffeeScript.compile source.toString()
invoke 'test'
invoke 'compress'
task 'test', 'run the bundled tests', (cb) ->
nodeunit.reporters.default.run ['test']
task 'compress', 'uglify the resulting javascript', (cb) ->
result = UglifyJS.minify('lib/ipaddr.js')
fs.writeFileSync('ipaddr.min.js', result.code)

View File

@ -1,19 +0,0 @@
Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,161 +0,0 @@
# ipaddr.js — an IPv6 and IPv4 address manipulation library
ipaddr.js is a small (1.9K minified and gzipped) library for manipulating
IP addresses in JavaScript environments. It runs on both CommonJS runtimes
(e.g. [nodejs]) and in a web browser.
ipaddr.js allows you to verify and parse string representation of an IP
address, match it against a CIDR range or range list, determine if it falls
into some reserved ranges (examples include loopback and private ranges),
and convert between IPv4 and IPv4-mapped IPv6 addresses.
[nodejs]: http://nodejs.org
## Installation
`npm install ipaddr.js`
## API
ipaddr.js defines one object in the global scope: `ipaddr`. In CommonJS,
it is exported from the module:
```js
var ipaddr = require('ipaddr.js');
```
The API consists of several global methods and two classes: ipaddr.IPv6 and ipaddr.IPv4.
### Global methods
There are three global methods defined: `ipaddr.isValid`, `ipaddr.parse` and
`ipaddr.process`. All of them receive a string as a single parameter.
The `ipaddr.isValid` method returns `true` if the address is a valid IPv4 or
IPv6 address, and `false` otherwise. It does not throw any exceptions.
The `ipaddr.parse` method returns an object representing the IP address,
or throws an `Error` if the passed string is not a valid representation of an
IP address.
The `ipaddr.process` method works just like the `ipaddr.parse` one, but it
automatically converts IPv4-mapped IPv6 addresses to their IPv4 couterparts
before returning. It is useful when you have a Node.js instance listening
on an IPv6 socket, and the `net.ivp6.bindv6only` sysctl parameter (or its
equivalent on non-Linux OS) is set to 0. In this case, you can accept IPv4
connections on your IPv6-only socket, but the remote address will be mangled.
Use `ipaddr.process` method to automatically demangle it.
### Object representation
Parsing methods return an object which descends from `ipaddr.IPv6` or
`ipaddr.IPv4`. These objects share some properties, but most of them differ.
#### Shared properties
One can determine the type of address by calling `addr.kind()`. It will return
either `"ipv6"` or `"ipv4"`.
An address can be converted back to its string representation with `addr.toString()`.
Note that this method:
* does not return the original string used to create the object (in fact, there is
no way of getting that string)
* returns a compact representation (when it is applicable)
A `match(range, bits)` method can be used to check if the address falls into a
certain CIDR range.
Note that an address can be (obviously) matched only against an address of the same type.
For example:
```js
var addr = ipaddr.parse("2001:db8:1234::1");
var range = ipaddr.parse("2001:db8::");
addr.match(range, 32); // => true
```
Alternatively, `match` can also be called as `match([range, bits])`. In this way,
it can be used together with the `parseCIDR(string)` method, which parses an IP
address together with a CIDR range.
For example:
```js
var addr = ipaddr.parse("2001:db8:1234::1");
addr.match(ipaddr.parseCIDR("2001:db8::/32")); // => true
```
A `range()` method returns one of predefined names for several special ranges defined
by IP protocols. The exact names (and their respective CIDR ranges) can be looked up
in the source: [IPv6 ranges] and [IPv4 ranges]. Some common ones include `"unicast"`
(the default one) and `"reserved"`.
You can match against your own range list by using
`ipaddr.subnetMatch(address, rangeList, defaultName)` method. It can work with both
IPv6 and IPv4 addresses, and accepts a name-to-subnet map as the range list. For example:
```js
var rangeList = {
documentationOnly: [ ipaddr.parse('2001:db8::'), 32 ],
tunnelProviders: [
[ ipaddr.parse('2001:470::'), 32 ], // he.net
[ ipaddr.parse('2001:5c0::'), 32 ] // freenet6
]
};
ipaddr.subnetMatch(ipaddr.parse('2001:470:8:66::1'), rangeList, 'unknown'); // => "he.net"
```
The addresses can be converted to their byte representation with `toByteArray()`.
(Actually, JavaScript mostly does not know about byte buffers. They are emulated with
arrays of numbers, each in range of 0..255.)
```js
var bytes = ipaddr.parse('2a00:1450:8007::68').toByteArray(); // ipv6.google.com
bytes // => [42, 0x00, 0x14, 0x50, 0x80, 0x07, 0x00, <zeroes...>, 0x00, 0x68 ]
```
The `ipaddr.IPv4` and `ipaddr.IPv6` objects have some methods defined, too. All of them
have the same interface for both protocols, and are similar to global methods.
`ipaddr.IPvX.isValid(string)` can be used to check if the string is a valid address
for particular protocol, and `ipaddr.IPvX.parse(string)` is the error-throwing parser.
[IPv6 ranges]: https://github.com/whitequark/ipaddr.js/blob/master/src/ipaddr.coffee#L186
[IPv4 ranges]: https://github.com/whitequark/ipaddr.js/blob/master/src/ipaddr.coffee#L71
#### IPv6 properties
Sometimes you will want to convert IPv6 not to a compact string representation (with
the `::` substitution); the `toNormalizedString()` method will return an address where
all zeroes are explicit.
For example:
```js
var addr = ipaddr.parse("2001:0db8::0001");
addr.toString(); // => "2001:db8::1"
addr.toNormalizedString(); // => "2001:db8:0:0:0:0:0:1"
```
The `isIPv4MappedAddress()` method will return `true` if this address is an IPv4-mapped
one, and `toIPv4Address()` will return an IPv4 object address.
To access the underlying binary representation of the address, use `addr.parts`.
```js
var addr = ipaddr.parse("2001:db8:10::1234:DEAD");
addr.parts // => [0x2001, 0xdb8, 0x10, 0, 0, 0, 0x1234, 0xdead]
```
#### IPv4 properties
`toIPv4MappedAddress()` will return a corresponding IPv4-mapped IPv6 address.
To access the underlying representation of the address, use `addr.octets`.
```js
var addr = ipaddr.parse("192.168.1.1");
addr.octets // => [192, 168, 1, 1]
```

File diff suppressed because one or more lines are too long

View File

@ -1,439 +0,0 @@
(function() {
var expandIPv6, ipaddr, ipv4Part, ipv4Regexes, ipv6Part, ipv6Regexes, matchCIDR, root;
ipaddr = {};
root = this;
if ((typeof module !== "undefined" && module !== null) && module.exports) {
module.exports = ipaddr;
} else {
root['ipaddr'] = ipaddr;
}
matchCIDR = function(first, second, partSize, cidrBits) {
var part, shift;
if (first.length !== second.length) {
throw new Error("ipaddr: cannot match CIDR for objects with different lengths");
}
part = 0;
while (cidrBits > 0) {
shift = partSize - cidrBits;
if (shift < 0) {
shift = 0;
}
if (first[part] >> shift !== second[part] >> shift) {
return false;
}
cidrBits -= partSize;
part += 1;
}
return true;
};
ipaddr.subnetMatch = function(address, rangeList, defaultName) {
var rangeName, rangeSubnets, subnet, _i, _len;
if (defaultName == null) {
defaultName = 'unicast';
}
for (rangeName in rangeList) {
rangeSubnets = rangeList[rangeName];
if (toString.call(rangeSubnets[0]) !== '[object Array]') {
rangeSubnets = [rangeSubnets];
}
for (_i = 0, _len = rangeSubnets.length; _i < _len; _i++) {
subnet = rangeSubnets[_i];
if (address.match.apply(address, subnet)) {
return rangeName;
}
}
}
return defaultName;
};
ipaddr.IPv4 = (function() {
function IPv4(octets) {
var octet, _i, _len;
if (octets.length !== 4) {
throw new Error("ipaddr: ipv4 octet count should be 4");
}
for (_i = 0, _len = octets.length; _i < _len; _i++) {
octet = octets[_i];
if (!((0 <= octet && octet <= 255))) {
throw new Error("ipaddr: ipv4 octet is a byte");
}
}
this.octets = octets;
}
IPv4.prototype.kind = function() {
return 'ipv4';
};
IPv4.prototype.toString = function() {
return this.octets.join(".");
};
IPv4.prototype.toByteArray = function() {
return this.octets.slice(0);
};
IPv4.prototype.match = function(other, cidrRange) {
var _ref;
if (cidrRange === void 0) {
_ref = other, other = _ref[0], cidrRange = _ref[1];
}
if (other.kind() !== 'ipv4') {
throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");
}
return matchCIDR(this.octets, other.octets, 8, cidrRange);
};
IPv4.prototype.SpecialRanges = {
unspecified: [[new IPv4([0, 0, 0, 0]), 8]],
broadcast: [[new IPv4([255, 255, 255, 255]), 32]],
multicast: [[new IPv4([224, 0, 0, 0]), 4]],
linkLocal: [[new IPv4([169, 254, 0, 0]), 16]],
loopback: [[new IPv4([127, 0, 0, 0]), 8]],
"private": [[new IPv4([10, 0, 0, 0]), 8], [new IPv4([172, 16, 0, 0]), 12], [new IPv4([192, 168, 0, 0]), 16]],
reserved: [[new IPv4([192, 0, 0, 0]), 24], [new IPv4([192, 0, 2, 0]), 24], [new IPv4([192, 88, 99, 0]), 24], [new IPv4([198, 51, 100, 0]), 24], [new IPv4([203, 0, 113, 0]), 24], [new IPv4([240, 0, 0, 0]), 4]]
};
IPv4.prototype.range = function() {
return ipaddr.subnetMatch(this, this.SpecialRanges);
};
IPv4.prototype.toIPv4MappedAddress = function() {
return ipaddr.IPv6.parse("::ffff:" + (this.toString()));
};
return IPv4;
})();
ipv4Part = "(0?\\d+|0x[a-f0-9]+)";
ipv4Regexes = {
fourOctet: new RegExp("^" + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "$", 'i'),
longValue: new RegExp("^" + ipv4Part + "$", 'i')
};
ipaddr.IPv4.parser = function(string) {
var match, parseIntAuto, part, shift, value;
parseIntAuto = function(string) {
if (string[0] === "0" && string[1] !== "x") {
return parseInt(string, 8);
} else {
return parseInt(string);
}
};
if (match = string.match(ipv4Regexes.fourOctet)) {
return (function() {
var _i, _len, _ref, _results;
_ref = match.slice(1, 6);
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
_results.push(parseIntAuto(part));
}
return _results;
})();
} else if (match = string.match(ipv4Regexes.longValue)) {
value = parseIntAuto(match[1]);
if (value > 0xffffffff || value < 0) {
throw new Error("ipaddr: address outside defined range");
}
return ((function() {
var _i, _results;
_results = [];
for (shift = _i = 0; _i <= 24; shift = _i += 8) {
_results.push((value >> shift) & 0xff);
}
return _results;
})()).reverse();
} else {
return null;
}
};
ipaddr.IPv6 = (function() {
function IPv6(parts) {
var part, _i, _len;
if (parts.length !== 8) {
throw new Error("ipaddr: ipv6 part count should be 8");
}
for (_i = 0, _len = parts.length; _i < _len; _i++) {
part = parts[_i];
if (!((0 <= part && part <= 0xffff))) {
throw new Error("ipaddr: ipv6 part should fit to two octets");
}
}
this.parts = parts;
}
IPv6.prototype.kind = function() {
return 'ipv6';
};
IPv6.prototype.toString = function() {
var compactStringParts, part, pushPart, state, stringParts, _i, _len;
stringParts = (function() {
var _i, _len, _ref, _results;
_ref = this.parts;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
_results.push(part.toString(16));
}
return _results;
}).call(this);
compactStringParts = [];
pushPart = function(part) {
return compactStringParts.push(part);
};
state = 0;
for (_i = 0, _len = stringParts.length; _i < _len; _i++) {
part = stringParts[_i];
switch (state) {
case 0:
if (part === '0') {
pushPart('');
} else {
pushPart(part);
}
state = 1;
break;
case 1:
if (part === '0') {
state = 2;
} else {
pushPart(part);
}
break;
case 2:
if (part !== '0') {
pushPart('');
pushPart(part);
state = 3;
}
break;
case 3:
pushPart(part);
}
}
if (state === 2) {
pushPart('');
pushPart('');
}
return compactStringParts.join(":");
};
IPv6.prototype.toByteArray = function() {
var bytes, part, _i, _len, _ref;
bytes = [];
_ref = this.parts;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
bytes.push(part >> 8);
bytes.push(part & 0xff);
}
return bytes;
};
IPv6.prototype.toNormalizedString = function() {
var part;
return ((function() {
var _i, _len, _ref, _results;
_ref = this.parts;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
_results.push(part.toString(16));
}
return _results;
}).call(this)).join(":");
};
IPv6.prototype.match = function(other, cidrRange) {
var _ref;
if (cidrRange === void 0) {
_ref = other, other = _ref[0], cidrRange = _ref[1];
}
if (other.kind() !== 'ipv6') {
throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");
}
return matchCIDR(this.parts, other.parts, 16, cidrRange);
};
IPv6.prototype.SpecialRanges = {
unspecified: [new IPv6([0, 0, 0, 0, 0, 0, 0, 0]), 128],
linkLocal: [new IPv6([0xfe80, 0, 0, 0, 0, 0, 0, 0]), 10],
multicast: [new IPv6([0xff00, 0, 0, 0, 0, 0, 0, 0]), 8],
loopback: [new IPv6([0, 0, 0, 0, 0, 0, 0, 1]), 128],
uniqueLocal: [new IPv6([0xfc00, 0, 0, 0, 0, 0, 0, 0]), 7],
ipv4Mapped: [new IPv6([0, 0, 0, 0, 0, 0xffff, 0, 0]), 96],
rfc6145: [new IPv6([0, 0, 0, 0, 0xffff, 0, 0, 0]), 96],
rfc6052: [new IPv6([0x64, 0xff9b, 0, 0, 0, 0, 0, 0]), 96],
'6to4': [new IPv6([0x2002, 0, 0, 0, 0, 0, 0, 0]), 16],
teredo: [new IPv6([0x2001, 0, 0, 0, 0, 0, 0, 0]), 32],
reserved: [[new IPv6([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32]]
};
IPv6.prototype.range = function() {
return ipaddr.subnetMatch(this, this.SpecialRanges);
};
IPv6.prototype.isIPv4MappedAddress = function() {
return this.range() === 'ipv4Mapped';
};
IPv6.prototype.toIPv4Address = function() {
var high, low, _ref;
if (!this.isIPv4MappedAddress()) {
throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");
}
_ref = this.parts.slice(-2), high = _ref[0], low = _ref[1];
return new ipaddr.IPv4([high >> 8, high & 0xff, low >> 8, low & 0xff]);
};
return IPv6;
})();
ipv6Part = "(?:[0-9a-f]+::?)+";
ipv6Regexes = {
"native": new RegExp("^(::)?(" + ipv6Part + ")?([0-9a-f]+)?(::)?$", 'i'),
transitional: new RegExp(("^((?:" + ipv6Part + ")|(?:::)(?:" + ipv6Part + ")?)") + ("" + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "\\." + ipv4Part + "$"), 'i')
};
expandIPv6 = function(string, parts) {
var colonCount, lastColon, part, replacement, replacementCount;
if (string.indexOf('::') !== string.lastIndexOf('::')) {
return null;
}
colonCount = 0;
lastColon = -1;
while ((lastColon = string.indexOf(':', lastColon + 1)) >= 0) {
colonCount++;
}
if (string[0] === ':') {
colonCount--;
}
if (string[string.length - 1] === ':') {
colonCount--;
}
if (colonCount > parts) {
return null;
}
replacementCount = parts - colonCount;
replacement = ':';
while (replacementCount--) {
replacement += '0:';
}
string = string.replace('::', replacement);
if (string[0] === ':') {
string = string.slice(1);
}
if (string[string.length - 1] === ':') {
string = string.slice(0, -1);
}
return (function() {
var _i, _len, _ref, _results;
_ref = string.split(":");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
_results.push(parseInt(part, 16));
}
return _results;
})();
};
ipaddr.IPv6.parser = function(string) {
var match, parts;
if (string.match(ipv6Regexes['native'])) {
return expandIPv6(string, 8);
} else if (match = string.match(ipv6Regexes['transitional'])) {
parts = expandIPv6(match[1].slice(0, -1), 6);
if (parts) {
parts.push(parseInt(match[2]) << 8 | parseInt(match[3]));
parts.push(parseInt(match[4]) << 8 | parseInt(match[5]));
return parts;
}
}
return null;
};
ipaddr.IPv4.isIPv4 = ipaddr.IPv6.isIPv6 = function(string) {
return this.parser(string) !== null;
};
ipaddr.IPv4.isValid = ipaddr.IPv6.isValid = function(string) {
var e;
try {
new this(this.parser(string));
return true;
} catch (_error) {
e = _error;
return false;
}
};
ipaddr.IPv4.parse = ipaddr.IPv6.parse = function(string) {
var parts;
parts = this.parser(string);
if (parts === null) {
throw new Error("ipaddr: string is not formatted like ip address");
}
return new this(parts);
};
ipaddr.IPv4.parseCIDR = ipaddr.IPv6.parseCIDR = function(string) {
var match;
if (match = string.match(/^(.+)\/(\d+)$/)) {
return [this.parse(match[1]), parseInt(match[2])];
}
throw new Error("ipaddr: string is not formatted like a CIDR range");
};
ipaddr.isValid = function(string) {
return ipaddr.IPv6.isValid(string) || ipaddr.IPv4.isValid(string);
};
ipaddr.parse = function(string) {
if (ipaddr.IPv6.isValid(string)) {
return ipaddr.IPv6.parse(string);
} else if (ipaddr.IPv4.isValid(string)) {
return ipaddr.IPv4.parse(string);
} else {
throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format");
}
};
ipaddr.parseCIDR = function(string) {
var e;
try {
return ipaddr.IPv6.parseCIDR(string);
} catch (_error) {
e = _error;
try {
return ipaddr.IPv4.parseCIDR(string);
} catch (_error) {
e = _error;
throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format");
}
}
};
ipaddr.process = function(string) {
var addr;
addr = this.parse(string);
if (addr.kind() === 'ipv6' && addr.isIPv4MappedAddress()) {
return addr.toIPv4Address();
} else {
return addr;
}
};
}).call(this);

View File

@ -1,58 +0,0 @@
{
"name": "ipaddr.js",
"description": "A library for manipulating IPv4 and IPv6 addresses in JavaScript.",
"version": "1.0.1",
"author": {
"name": "Peter Zotov",
"email": "whitequark@whitequark.org"
},
"directories": {
"lib": "./lib"
},
"dependencies": {},
"devDependencies": {
"coffee-script": "~1.6",
"nodeunit": "~0.5.3",
"uglify-js": "latest"
},
"scripts": {
"test": "cake build test"
},
"keywords": [
"ip",
"ipv4",
"ipv6"
],
"repository": {
"type": "git",
"url": "git://github.com/whitequark/ipaddr.js"
},
"main": "./lib/ipaddr",
"engines": {
"node": ">= 0.2.5"
},
"license": "MIT",
"gitHead": "0a5a26d9317a58d67047e7f32b5b1bbe7f2f7fbf",
"bugs": {
"url": "https://github.com/whitequark/ipaddr.js/issues"
},
"_id": "ipaddr.js@1.0.1",
"_shasum": "5f38801dc73e0400fc7076386f6ed5215fbd8f95",
"_from": "ipaddr.js@1.0.1",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "whitequark",
"email": "whitequark@whitequark.org"
},
"maintainers": [
{
"name": "whitequark",
"email": "whitequark@whitequark.org"
}
],
"dist": {
"shasum": "5f38801dc73e0400fc7076386f6ed5215fbd8f95",
"tarball": "http://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.1.tgz"
},
"_resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.1.tgz"
}

View File

@ -1,374 +0,0 @@
# Define the main object
ipaddr = {}
root = this
# Export for both the CommonJS and browser-like environment
if module? && module.exports
module.exports = ipaddr
else
root['ipaddr'] = ipaddr
# A generic CIDR (Classless Inter-Domain Routing) RFC1518 range matcher.
matchCIDR = (first, second, partSize, cidrBits) ->
if first.length != second.length
throw new Error "ipaddr: cannot match CIDR for objects with different lengths"
part = 0
while cidrBits > 0
shift = partSize - cidrBits
shift = 0 if shift < 0
if first[part] >> shift != second[part] >> shift
return false
cidrBits -= partSize
part += 1
return true
# An utility function to ease named range matching. See examples below.
ipaddr.subnetMatch = (address, rangeList, defaultName='unicast') ->
for rangeName, rangeSubnets of rangeList
# ECMA5 Array.isArray isn't available everywhere
if toString.call(rangeSubnets[0]) != '[object Array]'
rangeSubnets = [ rangeSubnets ]
for subnet in rangeSubnets
return rangeName if address.match.apply(address, subnet)
return defaultName
# An IPv4 address (RFC791).
class ipaddr.IPv4
# Constructs a new IPv4 address from an array of four octets.
# Verifies the input.
constructor: (octets) ->
if octets.length != 4
throw new Error "ipaddr: ipv4 octet count should be 4"
for octet in octets
if !(0 <= octet <= 255)
throw new Error "ipaddr: ipv4 octet is a byte"
@octets = octets
# The 'kind' method exists on both IPv4 and IPv6 classes.
kind: ->
return 'ipv4'
# Returns the address in convenient, decimal-dotted format.
toString: ->
return @octets.join "."
# Returns an array of byte-sized values in network order
toByteArray: ->
return @octets.slice(0) # octets.clone
# Checks if this address matches other one within given CIDR range.
match: (other, cidrRange) ->
if cidrRange == undefined
[other, cidrRange] = other
if other.kind() != 'ipv4'
throw new Error "ipaddr: cannot match ipv4 address with non-ipv4 one"
return matchCIDR(this.octets, other.octets, 8, cidrRange)
# Special IPv4 address ranges.
SpecialRanges:
unspecified: [
[ new IPv4([0, 0, 0, 0]), 8 ]
]
broadcast: [
[ new IPv4([255, 255, 255, 255]), 32 ]
]
multicast: [ # RFC3171
[ new IPv4([224, 0, 0, 0]), 4 ]
]
linkLocal: [ # RFC3927
[ new IPv4([169, 254, 0, 0]), 16 ]
]
loopback: [ # RFC5735
[ new IPv4([127, 0, 0, 0]), 8 ]
]
private: [ # RFC1918
[ new IPv4([10, 0, 0, 0]), 8 ]
[ new IPv4([172, 16, 0, 0]), 12 ]
[ new IPv4([192, 168, 0, 0]), 16 ]
]
reserved: [ # Reserved and testing-only ranges; RFCs 5735, 5737, 2544, 1700
[ new IPv4([192, 0, 0, 0]), 24 ]
[ new IPv4([192, 0, 2, 0]), 24 ]
[ new IPv4([192, 88, 99, 0]), 24 ]
[ new IPv4([198, 51, 100, 0]), 24 ]
[ new IPv4([203, 0, 113, 0]), 24 ]
[ new IPv4([240, 0, 0, 0]), 4 ]
]
# Checks if the address corresponds to one of the special ranges.
range: ->
return ipaddr.subnetMatch(this, @SpecialRanges)
# Convrets this IPv4 address to an IPv4-mapped IPv6 address.
toIPv4MappedAddress: ->
return ipaddr.IPv6.parse "::ffff:#{@toString()}"
# A list of regular expressions that match arbitrary IPv4 addresses,
# for which a number of weird notations exist.
# Note that an address like 0010.0xa5.1.1 is considered legal.
ipv4Part = "(0?\\d+|0x[a-f0-9]+)"
ipv4Regexes =
fourOctet: new RegExp "^#{ipv4Part}\\.#{ipv4Part}\\.#{ipv4Part}\\.#{ipv4Part}$", 'i'
longValue: new RegExp "^#{ipv4Part}$", 'i'
# Classful variants (like a.b, where a is an octet, and b is a 24-bit
# value representing last three octets; this corresponds to a class C
# address) are omitted due to classless nature of modern Internet.
ipaddr.IPv4.parser = (string) ->
parseIntAuto = (string) ->
if string[0] == "0" && string[1] != "x"
parseInt(string, 8)
else
parseInt(string)
# parseInt recognizes all that octal & hexadecimal weirdness for us
if match = string.match(ipv4Regexes.fourOctet)
return (parseIntAuto(part) for part in match[1..5])
else if match = string.match(ipv4Regexes.longValue)
value = parseIntAuto(match[1])
if value > 0xffffffff || value < 0
throw new Error "ipaddr: address outside defined range"
return ((value >> shift) & 0xff for shift in [0..24] by 8).reverse()
else
return null
# An IPv6 address (RFC2460)
class ipaddr.IPv6
# Constructs an IPv6 address from an array of eight 16-bit parts.
# Throws an error if the input is invalid.
constructor: (parts) ->
if parts.length != 8
throw new Error "ipaddr: ipv6 part count should be 8"
for part in parts
if !(0 <= part <= 0xffff)
throw new Error "ipaddr: ipv6 part should fit to two octets"
@parts = parts
# The 'kind' method exists on both IPv4 and IPv6 classes.
kind: ->
return 'ipv6'
# Returns the address in compact, human-readable format like
# 2001:db8:8:66::1
toString: ->
stringParts = (part.toString(16) for part in @parts)
compactStringParts = []
pushPart = (part) -> compactStringParts.push part
state = 0
for part in stringParts
switch state
when 0
if part == '0'
pushPart('')
else
pushPart(part)
state = 1
when 1
if part == '0'
state = 2
else
pushPart(part)
when 2
unless part == '0'
pushPart('')
pushPart(part)
state = 3
when 3
pushPart(part)
if state == 2
pushPart('')
pushPart('')
return compactStringParts.join ":"
# Returns an array of byte-sized values in network order
toByteArray: ->
bytes = []
for part in @parts
bytes.push(part >> 8)
bytes.push(part & 0xff)
return bytes
# Returns the address in expanded format with all zeroes included, like
# 2001:db8:8:66:0:0:0:1
toNormalizedString: ->
return (part.toString(16) for part in @parts).join ":"
# Checks if this address matches other one within given CIDR range.
match: (other, cidrRange) ->
if cidrRange == undefined
[other, cidrRange] = other
if other.kind() != 'ipv6'
throw new Error "ipaddr: cannot match ipv6 address with non-ipv6 one"
return matchCIDR(this.parts, other.parts, 16, cidrRange)
# Special IPv6 ranges
SpecialRanges:
unspecified: [ new IPv6([0, 0, 0, 0, 0, 0, 0, 0]), 128 ] # RFC4291, here and after
linkLocal: [ new IPv6([0xfe80, 0, 0, 0, 0, 0, 0, 0]), 10 ]
multicast: [ new IPv6([0xff00, 0, 0, 0, 0, 0, 0, 0]), 8 ]
loopback: [ new IPv6([0, 0, 0, 0, 0, 0, 0, 1]), 128 ]
uniqueLocal: [ new IPv6([0xfc00, 0, 0, 0, 0, 0, 0, 0]), 7 ]
ipv4Mapped: [ new IPv6([0, 0, 0, 0, 0, 0xffff, 0, 0]), 96 ]
rfc6145: [ new IPv6([0, 0, 0, 0, 0xffff, 0, 0, 0]), 96 ] # RFC6145
rfc6052: [ new IPv6([0x64, 0xff9b, 0, 0, 0, 0, 0, 0]), 96 ] # RFC6052
'6to4': [ new IPv6([0x2002, 0, 0, 0, 0, 0, 0, 0]), 16 ] # RFC3056
teredo: [ new IPv6([0x2001, 0, 0, 0, 0, 0, 0, 0]), 32 ] # RFC6052, RFC6146
reserved: [
[ new IPv6([ 0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]), 32 ] # RFC4291
]
# Checks if the address corresponds to one of the special ranges.
range: ->
return ipaddr.subnetMatch(this, @SpecialRanges)
# Checks if this address is an IPv4-mapped IPv6 address.
isIPv4MappedAddress: ->
return @range() == 'ipv4Mapped'
# Converts this address to IPv4 address if it is an IPv4-mapped IPv6 address.
# Throws an error otherwise.
toIPv4Address: ->
unless @isIPv4MappedAddress()
throw new Error "ipaddr: trying to convert a generic ipv6 address to ipv4"
[high, low] = @parts[-2..-1]
return new ipaddr.IPv4([high >> 8, high & 0xff, low >> 8, low & 0xff])
# IPv6-matching regular expressions.
# For IPv6, the task is simpler: it is enough to match the colon-delimited
# hexadecimal IPv6 and a transitional variant with dotted-decimal IPv4 at
# the end.
ipv6Part = "(?:[0-9a-f]+::?)+"
ipv6Regexes =
native: new RegExp "^(::)?(#{ipv6Part})?([0-9a-f]+)?(::)?$", 'i'
transitional: new RegExp "^((?:#{ipv6Part})|(?:::)(?:#{ipv6Part})?)" +
"#{ipv4Part}\\.#{ipv4Part}\\.#{ipv4Part}\\.#{ipv4Part}$", 'i'
# Expand :: in an IPv6 address or address part consisting of `parts` groups.
expandIPv6 = (string, parts) ->
# More than one '::' means invalid adddress
if string.indexOf('::') != string.lastIndexOf('::')
return null
# How many parts do we already have?
colonCount = 0
lastColon = -1
while (lastColon = string.indexOf(':', lastColon + 1)) >= 0
colonCount++
# 0::0 is two parts more than ::
colonCount-- if string[0] == ':'
colonCount-- if string[string.length-1] == ':'
# The following loop would hang if colonCount > parts
if colonCount > parts
return null
# replacement = ':' + '0:' * (parts - colonCount)
replacementCount = parts - colonCount
replacement = ':'
while replacementCount--
replacement += '0:'
# Insert the missing zeroes
string = string.replace('::', replacement)
# Trim any garbage which may be hanging around if :: was at the edge in
# the source string
string = string[1..-1] if string[0] == ':'
string = string[0..-2] if string[string.length-1] == ':'
return (parseInt(part, 16) for part in string.split(":"))
# Parse an IPv6 address.
ipaddr.IPv6.parser = (string) ->
if string.match(ipv6Regexes['native'])
return expandIPv6(string, 8)
else if match = string.match(ipv6Regexes['transitional'])
parts = expandIPv6(match[1][0..-2], 6)
if parts
parts.push(parseInt(match[2]) << 8 | parseInt(match[3]))
parts.push(parseInt(match[4]) << 8 | parseInt(match[5]))
return parts
return null
# Checks if a given string is formatted like IPv4/IPv6 address.
ipaddr.IPv4.isIPv4 = ipaddr.IPv6.isIPv6 = (string) ->
return @parser(string) != null
# Checks if a given string is a valid IPv4/IPv6 address.
ipaddr.IPv4.isValid = ipaddr.IPv6.isValid = (string) ->
try
new this(@parser(string))
return true
catch e
return false
# Tries to parse and validate a string with IPv4/IPv6 address.
# Throws an error if it fails.
ipaddr.IPv4.parse = ipaddr.IPv6.parse = (string) ->
parts = @parser(string)
if parts == null
throw new Error "ipaddr: string is not formatted like ip address"
return new this(parts)
ipaddr.IPv4.parseCIDR = ipaddr.IPv6.parseCIDR = (string) ->
if match = string.match(/^(.+)\/(\d+)$/)
return [@parse(match[1]), parseInt(match[2])]
throw new Error "ipaddr: string is not formatted like a CIDR range"
# Checks if the address is valid IP address
ipaddr.isValid = (string) ->
return ipaddr.IPv6.isValid(string) || ipaddr.IPv4.isValid(string)
# Try to parse an address and throw an error if it is impossible
ipaddr.parse = (string) ->
if ipaddr.IPv6.isValid(string)
return ipaddr.IPv6.parse(string)
else if ipaddr.IPv4.isValid(string)
return ipaddr.IPv4.parse(string)
else
throw new Error "ipaddr: the address has neither IPv6 nor IPv4 format"
ipaddr.parseCIDR = (string) ->
try
return ipaddr.IPv6.parseCIDR(string)
catch e
try
return ipaddr.IPv4.parseCIDR(string)
catch e
throw new Error "ipaddr: the address has neither IPv6 nor IPv4 CIDR format"
# Parse an address and return plain IPv4 address if it is an IPv4-mapped address
ipaddr.process = (string) ->
addr = @parse(string)
if addr.kind() == 'ipv6' && addr.isIPv4MappedAddress()
return addr.toIPv4Address()
else
return addr

Some files were not shown because too many files have changed in this diff Show More