This commit is contained in:
2015-11-02 11:36:10 +01:00
commit 08cd6febee
1419 changed files with 221401 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
1.2.13 / 2015-09-06
===================
* deps: mime-types@~2.1.6
- deps: mime-db@~1.18.0
1.2.12 / 2015-07-30
===================
* deps: mime-types@~2.1.4
- deps: mime-db@~1.16.0
1.2.11 / 2015-07-16
===================
* deps: mime-types@~2.1.3
- deps: mime-db@~1.15.0
1.2.10 / 2015-07-01
===================
* deps: mime-types@~2.1.2
- deps: mime-db@~1.14.0
1.2.9 / 2015-06-08
==================
* deps: mime-types@~2.1.1
- perf: fix deopt during mapping
1.2.8 / 2015-06-07
==================
* deps: mime-types@~2.1.0
- deps: mime-db@~1.13.0
* perf: avoid argument reassignment & argument slice
* perf: avoid negotiator recursive construction
* perf: enable strict mode
* perf: remove unnecessary bitwise operator
1.2.7 / 2015-05-10
==================
* deps: negotiator@0.5.3
- Fix media type parameter matching to be case-insensitive
1.2.6 / 2015-05-07
==================
* deps: mime-types@~2.0.11
- deps: mime-db@~1.9.1
* deps: negotiator@0.5.2
- Fix comparing media types with quoted values
- Fix splitting media types with quoted commas
1.2.5 / 2015-03-13
==================
* deps: mime-types@~2.0.10
- deps: mime-db@~1.8.0
1.2.4 / 2015-02-14
==================
* Support Node.js 0.6
* deps: mime-types@~2.0.9
- deps: mime-db@~1.7.0
* deps: negotiator@0.5.1
- Fix preference sorting to be stable for long acceptable lists
1.2.3 / 2015-01-31
==================
* deps: mime-types@~2.0.8
- deps: mime-db@~1.6.0
1.2.2 / 2014-12-30
==================
* deps: mime-types@~2.0.7
- deps: mime-db@~1.5.0
1.2.1 / 2014-12-30
==================
* deps: mime-types@~2.0.5
- deps: mime-db@~1.3.1
1.2.0 / 2014-12-19
==================
* deps: negotiator@0.5.0
- Fix list return order when large accepted list
- Fix missing identity encoding when q=0 exists
- Remove dynamic building of Negotiator class
1.1.4 / 2014-12-10
==================
* deps: mime-types@~2.0.4
- deps: mime-db@~1.3.0
1.1.3 / 2014-11-09
==================
* deps: mime-types@~2.0.3
- deps: mime-db@~1.2.0
1.1.2 / 2014-10-14
==================
* deps: negotiator@0.4.9
- Fix error when media type has invalid parameter
1.1.1 / 2014-09-28
==================
* deps: mime-types@~2.0.2
- deps: mime-db@~1.1.0
* deps: negotiator@0.4.8
- Fix all negotiations to be case-insensitive
- Stable sort preferences of same quality according to client order
1.1.0 / 2014-09-02
==================
* update `mime-types`
1.0.7 / 2014-07-04
==================
* Fix wrong type returned from `type` when match after unknown extension
1.0.6 / 2014-06-24
==================
* deps: negotiator@0.4.7
1.0.5 / 2014-06-20
==================
* fix crash when unknown extension given
1.0.4 / 2014-06-19
==================
* use `mime-types`
1.0.3 / 2014-06-11
==================
* deps: negotiator@0.4.6
- Order by specificity when quality is the same
1.0.2 / 2014-05-29
==================
* Fix interpretation when header not in request
* deps: pin negotiator@0.4.5
1.0.1 / 2014-01-18
==================
* Identity encoding isn't always acceptable
* deps: negotiator@~0.4.0
1.0.0 / 2013-12-27
==================
* Genesis
+23
View File
@@ -0,0 +1,23 @@
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Copyright (c) 2015 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.
+135
View File
@@ -0,0 +1,135 @@
# accepts
[![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]
Higher level content negotiation based on [negotiator](https://www.npmjs.com/package/negotiator). Extracted from [koa](https://www.npmjs.com/package/koa) for general use.
In addition to negotiator, it allows:
- Allows types as an array or arguments list, ie `(['text/html', 'application/json'])` as well as `('text/html', 'application/json')`.
- Allows type shorthands such as `json`.
- Returns `false` when no types match
- Treats non-existent headers as `*`
## Installation
```sh
npm install accepts
```
## API
```js
var accepts = require('accepts')
```
### accepts(req)
Create a new `Accepts` object for the given `req`.
#### .charset(charsets)
Return the first accepted charset. If nothing in `charsets` is accepted,
then `false` is returned.
#### .charsets()
Return the charsets that the request accepts, in the order of the client's
preference (most preferred first).
#### .encoding(encodings)
Return the first accepted encoding. If nothing in `encodings` is accepted,
then `false` is returned.
#### .encodings()
Return the encodings that the request accepts, in the order of the client's
preference (most preferred first).
#### .language(languages)
Return the first accepted language. If nothing in `languages` is accepted,
then `false` is returned.
#### .languages()
Return the languages that the request accepts, in the order of the client's
preference (most preferred first).
#### .type(types)
Return the first accepted type (and it is returned as the same text as what
appears in the `types` array). If nothing in `types` is accepted, then `false`
is returned.
The `types` array can contain full MIME types or file extensions. Any value
that is not a full MIME types is passed to `require('mime-types').lookup`.
#### .types()
Return the types that the request accepts, in the order of the client's
preference (most preferred first).
## Examples
### Simple type negotiation
This simple example shows how to use `accepts` to return a different typed
respond body based on what the client wants to accept. The server lists it's
preferences in order and will get back the best match between the client and
server.
```js
var accepts = require('accepts')
var http = require('http')
function app(req, res) {
var accept = accepts(req)
// the order of this list is significant; should be server preferred order
switch(accept.type(['json', 'html'])) {
case 'json':
res.setHeader('Content-Type', 'application/json')
res.write('{"hello":"world!"}')
break
case 'html':
res.setHeader('Content-Type', 'text/html')
res.write('<b>hello, world!</b>')
break
default:
// the fallback is text/plain, so no need to specify it above
res.setHeader('Content-Type', 'text/plain')
res.write('hello, world!')
break
}
res.end()
}
http.createServer(app).listen(3000)
```
You can test this out with the cURL program:
```sh
curl -I -H'Accept: text/html' http://localhost:3000/
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/accepts.svg
[npm-url]: https://npmjs.org/package/accepts
[node-version-image]: https://img.shields.io/node/v/accepts.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/accepts/master.svg
[travis-url]: https://travis-ci.org/jshttp/accepts
[coveralls-image]: https://img.shields.io/coveralls/jshttp/accepts/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/accepts
[downloads-image]: https://img.shields.io/npm/dm/accepts.svg
[downloads-url]: https://npmjs.org/package/accepts
+231
View File
@@ -0,0 +1,231 @@
/*!
* accepts
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var Negotiator = require('negotiator')
var mime = require('mime-types')
/**
* Module exports.
* @public
*/
module.exports = Accepts
/**
* Create a new Accepts object for the given req.
*
* @param {object} req
* @public
*/
function Accepts(req) {
if (!(this instanceof Accepts))
return new Accepts(req)
this.headers = req.headers
this.negotiator = new Negotiator(req)
}
/**
* 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" or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
*
* Examples:
*
* // Accept: text/html
* this.types('html');
* // => "html"
*
* // Accept: text/*, application/json
* this.types('html');
* // => "html"
* this.types('text/html');
* // => "text/html"
* this.types('json', 'text');
* // => "json"
* this.types('application/json');
* // => "application/json"
*
* // Accept: text/*, application/json
* this.types('image/png');
* this.types('png');
* // => undefined
*
* // Accept: text/*;q=.5, application/json
* this.types(['html', 'json']);
* this.types('html', 'json');
* // => "json"
*
* @param {String|Array} types...
* @return {String|Array|Boolean}
* @public
*/
Accepts.prototype.type =
Accepts.prototype.types = function (types_) {
var types = types_
// support flattened arguments
if (types && !Array.isArray(types)) {
types = new Array(arguments.length)
for (var i = 0; i < types.length; i++) {
types[i] = arguments[i]
}
}
// no types, return all requested types
if (!types || types.length === 0) {
return this.negotiator.mediaTypes()
}
if (!this.headers.accept) return types[0];
var mimes = types.map(extToMime);
var accepts = this.negotiator.mediaTypes(mimes.filter(validMime));
var first = accepts[0];
if (!first) return false;
return types[mimes.indexOf(first)];
}
/**
* Return accepted encodings or best fit based on `encodings`.
*
* Given `Accept-Encoding: gzip, deflate`
* an array sorted by quality is returned:
*
* ['gzip', 'deflate']
*
* @param {String|Array} encodings...
* @return {String|Array}
* @public
*/
Accepts.prototype.encoding =
Accepts.prototype.encodings = function (encodings_) {
var encodings = encodings_
// support flattened arguments
if (encodings && !Array.isArray(encodings)) {
encodings = new Array(arguments.length)
for (var i = 0; i < encodings.length; i++) {
encodings[i] = arguments[i]
}
}
// no encodings, return all requested encodings
if (!encodings || encodings.length === 0) {
return this.negotiator.encodings()
}
return this.negotiator.encodings(encodings)[0] || false
}
/**
* Return accepted charsets or best fit based on `charsets`.
*
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
* an array sorted by quality is returned:
*
* ['utf-8', 'utf-7', 'iso-8859-1']
*
* @param {String|Array} charsets...
* @return {String|Array}
* @public
*/
Accepts.prototype.charset =
Accepts.prototype.charsets = function (charsets_) {
var charsets = charsets_
// support flattened arguments
if (charsets && !Array.isArray(charsets)) {
charsets = new Array(arguments.length)
for (var i = 0; i < charsets.length; i++) {
charsets[i] = arguments[i]
}
}
// no charsets, return all requested charsets
if (!charsets || charsets.length === 0) {
return this.negotiator.charsets()
}
return this.negotiator.charsets(charsets)[0] || false
}
/**
* Return accepted languages or best fit based on `langs`.
*
* Given `Accept-Language: en;q=0.8, es, pt`
* an array sorted by quality is returned:
*
* ['es', 'pt', 'en']
*
* @param {String|Array} langs...
* @return {Array|String}
* @public
*/
Accepts.prototype.lang =
Accepts.prototype.langs =
Accepts.prototype.language =
Accepts.prototype.languages = function (languages_) {
var languages = languages_
// support flattened arguments
if (languages && !Array.isArray(languages)) {
languages = new Array(arguments.length)
for (var i = 0; i < languages.length; i++) {
languages[i] = arguments[i]
}
}
// no languages, return all requested languages
if (!languages || languages.length === 0) {
return this.negotiator.languages()
}
return this.negotiator.languages(languages)[0] || false
}
/**
* Convert extnames to mime.
*
* @param {String} type
* @return {String}
* @private
*/
function extToMime(type) {
return type.indexOf('/') === -1
? mime.lookup(type)
: type
}
/**
* Check if mime is valid.
*
* @param {String} type
* @return {String}
* @private
*/
function validMime(type) {
return typeof type === 'string';
}
@@ -0,0 +1,171 @@
2.1.7 / 2015-09-20
==================
* deps: mime-db@~1.19.0
- Add new mime types
2.1.6 / 2015-09-03
==================
* deps: mime-db@~1.18.0
- Add new mime types
2.1.5 / 2015-08-20
==================
* deps: mime-db@~1.17.0
- Add new mime types
2.1.4 / 2015-07-30
==================
* deps: mime-db@~1.16.0
- Add new mime types
2.1.3 / 2015-07-13
==================
* deps: mime-db@~1.15.0
- Add new mime types
2.1.2 / 2015-06-25
==================
* deps: mime-db@~1.14.0
- Add new mime types
2.1.1 / 2015-06-08
==================
* perf: fix deopt during mapping
2.1.0 / 2015-06-07
==================
* Fix incorrectly treating extension-less file name as extension
- i.e. `'path/to/json'` will no longer return `application/json`
* Fix `.charset(type)` to accept parameters
* Fix `.charset(type)` to match case-insensitive
* Improve generation of extension to MIME mapping
* Refactor internals for readability and no argument reassignment
* Prefer `application/*` MIME types from the same source
* Prefer any type over `application/octet-stream`
* deps: mime-db@~1.13.0
- Add nginx as a source
- Add new mime types
2.0.14 / 2015-06-06
===================
* deps: mime-db@~1.12.0
- Add new mime types
2.0.13 / 2015-05-31
===================
* deps: mime-db@~1.11.0
- Add new mime types
2.0.12 / 2015-05-19
===================
* deps: mime-db@~1.10.0
- Add new mime types
2.0.11 / 2015-05-05
===================
* deps: mime-db@~1.9.1
- Add new mime types
2.0.10 / 2015-03-13
===================
* deps: mime-db@~1.8.0
- Add new mime types
2.0.9 / 2015-02-09
==================
* deps: mime-db@~1.7.0
- Add new mime types
- Community extensions ownership transferred from `node-mime`
2.0.8 / 2015-01-29
==================
* deps: mime-db@~1.6.0
- Add new mime types
2.0.7 / 2014-12-30
==================
* deps: mime-db@~1.5.0
- Add new mime types
- Fix various invalid MIME type entries
2.0.6 / 2014-12-30
==================
* deps: mime-db@~1.4.0
- Add new mime types
- Fix various invalid MIME type entries
- Remove example template MIME types
2.0.5 / 2014-12-29
==================
* deps: mime-db@~1.3.1
- Fix missing extensions
2.0.4 / 2014-12-10
==================
* deps: mime-db@~1.3.0
- Add new mime types
2.0.3 / 2014-11-09
==================
* deps: mime-db@~1.2.0
- Add new mime types
2.0.2 / 2014-09-28
==================
* deps: mime-db@~1.1.0
- Add new mime types
- Add additional compressible
- Update charsets
2.0.1 / 2014-09-07
==================
* Support Node.js 0.6
2.0.0 / 2014-09-02
==================
* Use `mime-db`
* Remove `.define()`
1.0.2 / 2014-08-04
==================
* Set charset=utf-8 for `text/javascript`
1.0.1 / 2014-06-24
==================
* Add `text/jsx` type
1.0.0 / 2014-05-12
==================
* Return `false` for unknown types
* Set charset=utf-8 for `application/json`
0.1.0 / 2014-05-02
==================
* Initial release
@@ -0,0 +1,23 @@
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Copyright (c) 2015 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.
@@ -0,0 +1,103 @@
# mime-types
[![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]
The ultimate javascript content-type utility.
Similar to [node-mime](https://github.com/broofa/node-mime), except:
- __No fallbacks.__ Instead of naively returning the first available type, `mime-types` simply returns `false`,
so do `var type = mime.lookup('unrecognized') || 'application/octet-stream'`.
- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.
- Additional mime types are added such as jade and stylus via [mime-db](https://github.com/jshttp/mime-db)
- No `.define()` functionality
Otherwise, the API is compatible.
## Install
```sh
$ npm install mime-types
```
## Adding Types
All mime types are based on [mime-db](https://github.com/jshttp/mime-db),
so open a PR there if you'd like to add mime types.
## API
```js
var mime = require('mime-types')
```
All functions return `false` if input is invalid or not found.
### mime.lookup(path)
Lookup the content-type associated with a file.
```js
mime.lookup('json') // 'application/json'
mime.lookup('.md') // 'text/x-markdown'
mime.lookup('file.html') // 'text/html'
mime.lookup('folder/file.js') // 'application/javascript'
mime.lookup('folder/.htaccess') // false
mime.lookup('cats') // false
```
### mime.contentType(type)
Create a full content-type header given a content-type or extension.
```js
mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
mime.contentType('file.json') // 'application/json; charset=utf-8'
// from a full path
mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'
```
### mime.extension(type)
Get the default extension for a content-type.
```js
mime.extension('application/octet-stream') // 'bin'
```
### mime.charset(type)
Lookup the implied default charset of a content-type.
```js
mime.charset('text/x-markdown') // 'UTF-8'
```
### var type = mime.types[extension]
A map of content-types by extension.
### [extensions...] = mime.extensions[type]
A map of extensions by content-type.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/mime-types.svg
[npm-url]: https://npmjs.org/package/mime-types
[node-version-image]: https://img.shields.io/node/v/mime-types.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/mime-types/master.svg
[travis-url]: https://travis-ci.org/jshttp/mime-types
[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-types/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/mime-types
[downloads-image]: https://img.shields.io/npm/dm/mime-types.svg
[downloads-url]: https://npmjs.org/package/mime-types
@@ -0,0 +1,188 @@
/*!
* mime-types
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var db = require('mime-db')
var extname = require('path').extname
/**
* Module variables.
* @private
*/
var extractTypeRegExp = /^\s*([^;\s]*)(?:;|\s|$)/
var textTypeRegExp = /^text\//i
/**
* Module exports.
* @public
*/
exports.charset = charset
exports.charsets = { lookup: charset }
exports.contentType = contentType
exports.extension = extension
exports.extensions = Object.create(null)
exports.lookup = lookup
exports.types = Object.create(null)
// Populate the extensions/types maps
populateMaps(exports.extensions, exports.types)
/**
* Get the default charset for a MIME type.
*
* @param {string} type
* @return {boolean|string}
*/
function charset(type) {
if (!type || typeof type !== 'string') {
return false
}
// TODO: use media-typer
var match = extractTypeRegExp.exec(type)
var mime = match && db[match[1].toLowerCase()]
if (mime && mime.charset) {
return mime.charset
}
// default text/* to utf-8
if (match && textTypeRegExp.test(match[1])) {
return 'UTF-8'
}
return false
}
/**
* Create a full Content-Type header given a MIME type or extension.
*
* @param {string} str
* @return {boolean|string}
*/
function contentType(str) {
// TODO: should this even be in this module?
if (!str || typeof str !== 'string') {
return false
}
var mime = str.indexOf('/') === -1
? exports.lookup(str)
: str
if (!mime) {
return false
}
// TODO: use content-type or other module
if (mime.indexOf('charset') === -1) {
var charset = exports.charset(mime)
if (charset) mime += '; charset=' + charset.toLowerCase()
}
return mime
}
/**
* Get the default extension for a MIME type.
*
* @param {string} type
* @return {boolean|string}
*/
function extension(type) {
if (!type || typeof type !== 'string') {
return false
}
// TODO: use media-typer
var match = extractTypeRegExp.exec(type)
// get extensions
var exts = match && exports.extensions[match[1].toLowerCase()]
if (!exts || !exts.length) {
return false
}
return exts[0]
}
/**
* Lookup the MIME type for a file path/extension.
*
* @param {string} path
* @return {boolean|string}
*/
function lookup(path) {
if (!path || typeof path !== 'string') {
return false
}
// get the extension ("ext" or ".ext" or full path)
var extension = extname('x.' + path)
.toLowerCase()
.substr(1)
if (!extension) {
return false
}
return exports.types[extension] || false
}
/**
* Populate the extensions and types maps.
* @private
*/
function populateMaps(extensions, types) {
// source preference (least -> most)
var preference = ['nginx', 'apache', undefined, 'iana']
Object.keys(db).forEach(function forEachMimeType(type) {
var mime = db[type]
var exts = mime.extensions
if (!exts || !exts.length) {
return
}
// mime -> extensions
extensions[type] = exts
// extension -> mime
for (var i = 0; i < exts.length; i++) {
var extension = exts[i]
if (types[extension]) {
var from = preference.indexOf(db[types[extension]].source)
var to = preference.indexOf(mime.source)
if (types[extension] !== 'application/octet-stream'
&& from > to || (from === to && types[extension].substr(0, 12) === 'application/')) {
// skip the remapping
continue
}
}
// set the extension -> mime
types[extension] = type
}
})
}
@@ -0,0 +1,274 @@
1.19.0 / 2015-09-17
===================
* Add `application/vnd.3gpp-prose-pc3ch+xml`
* Add `application/vnd.3gpp.srvcc-info+xml`
* Add `application/vnd.apple.pkpass`
* Add `application/vnd.drive+json`
1.18.0 / 2015-09-03
===================
* Add `application/pkcs12`
* Add `application/vnd.3gpp-prose+xml`
* Add `application/vnd.3gpp.mid-call+xml`
* Add `application/vnd.3gpp.state-and-event-info+xml`
* Add `application/vnd.anki`
* Add `application/vnd.firemonkeys.cloudcell`
* Add `application/vnd.openblox.game+xml`
* Add `application/vnd.openblox.game-binary`
1.17.0 / 2015-08-13
===================
* Add `application/x-msdos-program`
* Add `audio/g711-0`
* Add `image/vnd.mozilla.apng`
* Add extension `.exe` to `application/x-msdos-program`
1.16.0 / 2015-07-29
===================
* Add `application/vnd.uri-map`
1.15.0 / 2015-07-13
===================
* Add `application/x-httpd-php`
1.14.0 / 2015-06-25
===================
* Add `application/scim+json`
* Add `application/vnd.3gpp.ussd+xml`
* Add `application/vnd.biopax.rdf+xml`
* Add `text/x-processing`
1.13.0 / 2015-06-07
===================
* Add nginx as a source
* Add `application/x-cocoa`
* Add `application/x-java-archive-diff`
* Add `application/x-makeself`
* Add `application/x-perl`
* Add `application/x-pilot`
* Add `application/x-redhat-package-manager`
* Add `application/x-sea`
* Add `audio/x-m4a`
* Add `audio/x-realaudio`
* Add `image/x-jng`
* Add `text/mathml`
1.12.0 / 2015-06-05
===================
* Add `application/bdoc`
* Add `application/vnd.hyperdrive+json`
* Add `application/x-bdoc`
* Add extension `.rtf` to `text/rtf`
1.11.0 / 2015-05-31
===================
* Add `audio/wav`
* Add `audio/wave`
* Add extension `.litcoffee` to `text/coffeescript`
* Add extension `.sfd-hdstx` to `application/vnd.hydrostatix.sof-data`
* Add extension `.n-gage` to `application/vnd.nokia.n-gage.symbian.install`
1.10.0 / 2015-05-19
===================
* Add `application/vnd.balsamiq.bmpr`
* Add `application/vnd.microsoft.portable-executable`
* Add `application/x-ns-proxy-autoconfig`
1.9.1 / 2015-04-19
==================
* Remove `.json` extension from `application/manifest+json`
- This is causing bugs downstream
1.9.0 / 2015-04-19
==================
* Add `application/manifest+json`
* Add `application/vnd.micro+json`
* Add `image/vnd.zbrush.pcx`
* Add `image/x-ms-bmp`
1.8.0 / 2015-03-13
==================
* Add `application/vnd.citationstyles.style+xml`
* Add `application/vnd.fastcopy-disk-image`
* Add `application/vnd.gov.sk.xmldatacontainer+xml`
* Add extension `.jsonld` to `application/ld+json`
1.7.0 / 2015-02-08
==================
* Add `application/vnd.gerber`
* Add `application/vnd.msa-disk-image`
1.6.1 / 2015-02-05
==================
* Community extensions ownership transferred from `node-mime`
1.6.0 / 2015-01-29
==================
* Add `application/jose`
* Add `application/jose+json`
* Add `application/json-seq`
* Add `application/jwk+json`
* Add `application/jwk-set+json`
* Add `application/jwt`
* Add `application/rdap+json`
* Add `application/vnd.gov.sk.e-form+xml`
* Add `application/vnd.ims.imsccv1p3`
1.5.0 / 2014-12-30
==================
* Add `application/vnd.oracle.resource+json`
* Fix various invalid MIME type entries
- `application/mbox+xml`
- `application/oscp-response`
- `application/vwg-multiplexed`
- `audio/g721`
1.4.0 / 2014-12-21
==================
* Add `application/vnd.ims.imsccv1p2`
* Fix various invalid MIME type entries
- `application/vnd-acucobol`
- `application/vnd-curl`
- `application/vnd-dart`
- `application/vnd-dxr`
- `application/vnd-fdf`
- `application/vnd-mif`
- `application/vnd-sema`
- `application/vnd-wap-wmlc`
- `application/vnd.adobe.flash-movie`
- `application/vnd.dece-zip`
- `application/vnd.dvb_service`
- `application/vnd.micrografx-igx`
- `application/vnd.sealed-doc`
- `application/vnd.sealed-eml`
- `application/vnd.sealed-mht`
- `application/vnd.sealed-ppt`
- `application/vnd.sealed-tiff`
- `application/vnd.sealed-xls`
- `application/vnd.sealedmedia.softseal-html`
- `application/vnd.sealedmedia.softseal-pdf`
- `application/vnd.wap-slc`
- `application/vnd.wap-wbxml`
- `audio/vnd.sealedmedia.softseal-mpeg`
- `image/vnd-djvu`
- `image/vnd-svf`
- `image/vnd-wap-wbmp`
- `image/vnd.sealed-png`
- `image/vnd.sealedmedia.softseal-gif`
- `image/vnd.sealedmedia.softseal-jpg`
- `model/vnd-dwf`
- `model/vnd.parasolid.transmit-binary`
- `model/vnd.parasolid.transmit-text`
- `text/vnd-a`
- `text/vnd-curl`
- `text/vnd.wap-wml`
* Remove example template MIME types
- `application/example`
- `audio/example`
- `image/example`
- `message/example`
- `model/example`
- `multipart/example`
- `text/example`
- `video/example`
1.3.1 / 2014-12-16
==================
* Fix missing extensions
- `application/json5`
- `text/hjson`
1.3.0 / 2014-12-07
==================
* Add `application/a2l`
* Add `application/aml`
* Add `application/atfx`
* Add `application/atxml`
* Add `application/cdfx+xml`
* Add `application/dii`
* Add `application/json5`
* Add `application/lxf`
* Add `application/mf4`
* Add `application/vnd.apache.thrift.compact`
* Add `application/vnd.apache.thrift.json`
* Add `application/vnd.coffeescript`
* Add `application/vnd.enphase.envoy`
* Add `application/vnd.ims.imsccv1p1`
* Add `text/csv-schema`
* Add `text/hjson`
* Add `text/markdown`
* Add `text/yaml`
1.2.0 / 2014-11-09
==================
* Add `application/cea`
* Add `application/dit`
* Add `application/vnd.gov.sk.e-form+zip`
* Add `application/vnd.tmd.mediaflex.api+xml`
* Type `application/epub+zip` is now IANA-registered
1.1.2 / 2014-10-23
==================
* Rebuild database for `application/x-www-form-urlencoded` change
1.1.1 / 2014-10-20
==================
* Mark `application/x-www-form-urlencoded` as compressible.
1.1.0 / 2014-09-28
==================
* Add `application/font-woff2`
1.0.3 / 2014-09-25
==================
* Fix engine requirement in package
1.0.2 / 2014-09-25
==================
* Add `application/coap-group+json`
* Add `application/dcd`
* Add `application/vnd.apache.thrift.binary`
* Add `image/vnd.tencent.tap`
* Mark all JSON-derived types as compressible
* Update `text/vtt` data
1.0.1 / 2014-08-30
==================
* Fix extension ordering
1.0.0 / 2014-08-30
==================
* Add `application/atf`
* Add `application/merge-patch+json`
* Add `multipart/x-mixed-replace`
* Add `source: 'apache'` metadata
* Add `source: 'iana'` metadata
* Remove badly-assumed charset data
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 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.
@@ -0,0 +1,82 @@
# mime-db
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][travis-image]][travis-url]
[![Coverage Status][coveralls-image]][coveralls-url]
This is a database of all mime types.
It consists of a single, public JSON file and does not include any logic,
allowing it to remain as un-opinionated as possible with an API.
It aggregates data from the following sources:
- http://www.iana.org/assignments/media-types/media-types.xhtml
- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types
## Installation
```bash
npm install mime-db
```
### Database Download
If you're crazy enough to use this in the browser, you can just grab the
JSON file using [RawGit](https://rawgit.com/). It is recommended to replace
`master` with [a release tag](https://github.com/jshttp/mime-db/tags) as the
JSON format may change in the future.
```
https://cdn.rawgit.com/jshttp/mime-db/master/db.json
```
## Usage
```js
var db = require('mime-db');
// grab data on .js files
var data = db['application/javascript'];
```
## Data Structure
The JSON file is a map lookup for lowercased mime types.
Each mime type has the following properties:
- `.source` - where the mime type is defined.
If not set, it's probably a custom media type.
- `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
- `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
- `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)
- `.extensions[]` - known extensions associated with this mime type.
- `.compressible` - whether a file of this type is can be gzipped.
- `.charset` - the default charset associated with this type, if any.
If unknown, every property could be `undefined`.
## Contributing
To edit the database, only make PRs against `src/custom.json` or
`src/custom-suffix.json`.
To update the build, run `npm run build`.
## Adding Custom Media Types
The best way to get new media types included in this library is to register
them with the IANA. The community registration procedure is outlined in
[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types
registered with the IANA are automatically pulled into this library.
[npm-version-image]: https://img.shields.io/npm/v/mime-db.svg
[npm-downloads-image]: https://img.shields.io/npm/dm/mime-db.svg
[npm-url]: https://npmjs.org/package/mime-db
[travis-image]: https://img.shields.io/travis/jshttp/mime-db/master.svg
[travis-url]: https://travis-ci.org/jshttp/mime-db
[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-db/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
[node-image]: https://img.shields.io/node/v/mime-db.svg
[node-url]: http://nodejs.org/download/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = require('./db.json')
@@ -0,0 +1,76 @@
{
"name": "mime-db",
"description": "Media Type Database",
"version": "1.19.0",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
{
"name": "Robert Kieffer",
"email": "robert@broofa.com",
"url": "http://github.com/broofa"
}
],
"license": "MIT",
"keywords": [
"mime",
"db",
"type",
"types",
"database",
"charset",
"charsets"
],
"repository": {
"type": "git",
"url": "git://github.com/jshttp/mime-db"
},
"devDependencies": {
"bluebird": "2.10.0",
"co": "4.6.0",
"cogent": "1.0.1",
"csv-parse": "1.0.0",
"gnode": "0.1.1",
"istanbul": "0.3.20",
"mocha": "1.21.5",
"raw-body": "2.1.3",
"stream-to-array": "2"
},
"files": [
"HISTORY.md",
"LICENSE",
"README.md",
"db.json",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"build": "node scripts/build",
"fetch": "gnode scripts/fetch-apache && gnode scripts/fetch-iana && gnode scripts/fetch-nginx",
"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/",
"update": "npm run fetch && npm run build"
},
"readme": "# mime-db\n\n[![NPM Version][npm-version-image]][npm-url]\n[![NPM Downloads][npm-downloads-image]][npm-url]\n[![Node.js Version][node-image]][node-url]\n[![Build Status][travis-image]][travis-url]\n[![Coverage Status][coveralls-image]][coveralls-url]\n\nThis is a database of all mime types.\nIt consists of a single, public JSON file and does not include any logic,\nallowing it to remain as un-opinionated as possible with an API.\nIt aggregates data from the following sources:\n\n- http://www.iana.org/assignments/media-types/media-types.xhtml\n- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types\n- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types\n\n## Installation\n\n```bash\nnpm install mime-db\n```\n\n### Database Download\n\nIf you're crazy enough to use this in the browser, you can just grab the\nJSON file using [RawGit](https://rawgit.com/). It is recommended to replace\n`master` with [a release tag](https://github.com/jshttp/mime-db/tags) as the\nJSON format may change in the future.\n\n```\nhttps://cdn.rawgit.com/jshttp/mime-db/master/db.json\n```\n\n## Usage\n\n```js\nvar db = require('mime-db');\n\n// grab data on .js files\nvar data = db['application/javascript'];\n```\n\n## Data Structure\n\nThe JSON file is a map lookup for lowercased mime types.\nEach mime type has the following properties:\n\n- `.source` - where the mime type is defined.\n If not set, it's probably a custom media type.\n - `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)\n - `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)\n - `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)\n- `.extensions[]` - known extensions associated with this mime type.\n- `.compressible` - whether a file of this type is can be gzipped.\n- `.charset` - the default charset associated with this type, if any.\n\nIf unknown, every property could be `undefined`.\n\n## Contributing\n\nTo edit the database, only make PRs against `src/custom.json` or\n`src/custom-suffix.json`.\n\nTo update the build, run `npm run build`.\n\n## Adding Custom Media Types\n\nThe best way to get new media types included in this library is to register\nthem with the IANA. The community registration procedure is outlined in\n[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types\nregistered with the IANA are automatically pulled into this library.\n\n[npm-version-image]: https://img.shields.io/npm/v/mime-db.svg\n[npm-downloads-image]: https://img.shields.io/npm/dm/mime-db.svg\n[npm-url]: https://npmjs.org/package/mime-db\n[travis-image]: https://img.shields.io/travis/jshttp/mime-db/master.svg\n[travis-url]: https://travis-ci.org/jshttp/mime-db\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-db/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master\n[node-image]: https://img.shields.io/node/v/mime-db.svg\n[node-url]: http://nodejs.org/download/\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/mime-db/issues"
},
"homepage": "https://github.com/jshttp/mime-db",
"_id": "mime-db@1.19.0",
"dist": {
"shasum": "d600eeaa8e4a1dd59932991e17181a05170c54dd"
},
"_from": "mime-db@~1.19.0",
"_resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
}
@@ -0,0 +1,62 @@
{
"name": "mime-types",
"description": "The ultimate javascript content-type utility.",
"version": "2.1.7",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jeremiah Senkpiel",
"email": "fishrock123@rocketmail.com",
"url": "https://searchbeam.jit.su"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
}
],
"license": "MIT",
"keywords": [
"mime",
"types"
],
"repository": {
"type": "git",
"url": "git://github.com/jshttp/mime-types"
},
"dependencies": {
"mime-db": "~1.19.0"
},
"devDependencies": {
"istanbul": "0.3.20",
"mocha": "~1.21.5"
},
"files": [
"HISTORY.md",
"LICENSE",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec test/test.js",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/test.js",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot test/test.js"
},
"readme": "# mime-types\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nThe ultimate javascript content-type utility.\n\nSimilar to [node-mime](https://github.com/broofa/node-mime), except:\n\n- __No fallbacks.__ Instead of naively returning the first available type, `mime-types` simply returns `false`,\n so do `var type = mime.lookup('unrecognized') || 'application/octet-stream'`.\n- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.\n- Additional mime types are added such as jade and stylus via [mime-db](https://github.com/jshttp/mime-db)\n- No `.define()` functionality\n\nOtherwise, the API is compatible.\n\n## Install\n\n```sh\n$ npm install mime-types\n```\n\n## Adding Types\n\nAll mime types are based on [mime-db](https://github.com/jshttp/mime-db),\nso open a PR there if you'd like to add mime types.\n\n## API\n\n```js\nvar mime = require('mime-types')\n```\n\nAll functions return `false` if input is invalid or not found.\n\n### mime.lookup(path)\n\nLookup the content-type associated with a file.\n\n```js\nmime.lookup('json') // 'application/json'\nmime.lookup('.md') // 'text/x-markdown'\nmime.lookup('file.html') // 'text/html'\nmime.lookup('folder/file.js') // 'application/javascript'\nmime.lookup('folder/.htaccess') // false\n\nmime.lookup('cats') // false\n```\n\n### mime.contentType(type)\n\nCreate a full content-type header given a content-type or extension.\n\n```js\nmime.contentType('markdown') // 'text/x-markdown; charset=utf-8'\nmime.contentType('file.json') // 'application/json; charset=utf-8'\n\n// from a full path\nmime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'\n```\n\n### mime.extension(type)\n\nGet the default extension for a content-type.\n\n```js\nmime.extension('application/octet-stream') // 'bin'\n```\n\n### mime.charset(type)\n\nLookup the implied default charset of a content-type.\n\n```js\nmime.charset('text/x-markdown') // 'UTF-8'\n```\n\n### var type = mime.types[extension]\n\nA map of content-types by extension.\n\n### [extensions...] = mime.extensions[type]\n\nA map of extensions by content-type.\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/mime-types.svg\n[npm-url]: https://npmjs.org/package/mime-types\n[node-version-image]: https://img.shields.io/node/v/mime-types.svg\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/mime-types/master.svg\n[travis-url]: https://travis-ci.org/jshttp/mime-types\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-types/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/mime-types\n[downloads-image]: https://img.shields.io/npm/dm/mime-types.svg\n[downloads-url]: https://npmjs.org/package/mime-types\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/mime-types/issues"
},
"homepage": "https://github.com/jshttp/mime-types",
"_id": "mime-types@2.1.7",
"dist": {
"shasum": "055bc7633b2e96dd59cce047edb9beda1cd4d89e"
},
"_from": "mime-types@~2.1.6",
"_resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
}
@@ -0,0 +1,76 @@
0.5.3 / 2015-05-10
==================
* Fix media type parameter matching to be case-insensitive
0.5.2 / 2015-05-06
==================
* Fix comparing media types with quoted values
* Fix splitting media types with quoted commas
0.5.1 / 2015-02-14
==================
* Fix preference sorting to be stable for long acceptable lists
0.5.0 / 2014-12-18
==================
* Fix list return order when large accepted list
* Fix missing identity encoding when q=0 exists
* Remove dynamic building of Negotiator class
0.4.9 / 2014-10-14
==================
* Fix error when media type has invalid parameter
0.4.8 / 2014-09-28
==================
* Fix all negotiations to be case-insensitive
* Stable sort preferences of same quality according to client order
* Support Node.js 0.6
0.4.7 / 2014-06-24
==================
* Handle invalid provided languages
* Handle invalid provided media types
0.4.6 / 2014-06-11
==================
* Order by specificity when quality is the same
0.4.5 / 2014-05-29
==================
* Fix regression in empty header handling
0.4.4 / 2014-05-29
==================
* Fix behaviors when headers are not present
0.4.3 / 2014-04-16
==================
* Handle slashes on media params correctly
0.4.2 / 2014-02-28
==================
* Fix media type sorting
* Handle media types params strictly
0.4.1 / 2014-01-16
==================
* Use most specific matches
0.4.0 / 2014-01-09
==================
* Remove preferred prefix from methods
@@ -0,0 +1,24 @@
(The MIT License)
Copyright (c) 2012-2014 Federico Romero
Copyright (c) 2012-2014 Isaac Z. Schlueter
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.
@@ -0,0 +1,203 @@
# negotiator
[![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]
An HTTP content negotiator for Node.js
## Installation
```sh
$ npm install negotiator
```
## API
```js
var Negotiator = require('negotiator')
```
### Accept Negotiation
```js
availableMediaTypes = ['text/html', 'text/plain', 'application/json']
// The negotiator constructor receives a request object
negotiator = new Negotiator(request)
// Let's say Accept header is 'text/html, application/*;q=0.2, image/jpeg;q=0.8'
negotiator.mediaTypes()
// -> ['text/html', 'image/jpeg', 'application/*']
negotiator.mediaTypes(availableMediaTypes)
// -> ['text/html', 'application/json']
negotiator.mediaType(availableMediaTypes)
// -> 'text/html'
```
You can check a working example at `examples/accept.js`.
#### Methods
##### mediaType()
Returns the most preferred media type from the client.
##### mediaType(availableMediaType)
Returns the most preferred media type from a list of available media types.
##### mediaTypes()
Returns an array of preferred media types ordered by the client preference.
##### mediaTypes(availableMediaTypes)
Returns an array of preferred media types ordered by priority from a list of
available media types.
### Accept-Language Negotiation
```js
negotiator = new Negotiator(request)
availableLanguages = 'en', 'es', 'fr'
// Let's say Accept-Language header is 'en;q=0.8, es, pt'
negotiator.languages()
// -> ['es', 'pt', 'en']
negotiator.languages(availableLanguages)
// -> ['es', 'en']
language = negotiator.language(availableLanguages)
// -> 'es'
```
You can check a working example at `examples/language.js`.
#### Methods
##### language()
Returns the most preferred language from the client.
##### language(availableLanguages)
Returns the most preferred language from a list of available languages.
##### languages()
Returns an array of preferred languages ordered by the client preference.
##### languages(availableLanguages)
Returns an array of preferred languages ordered by priority from a list of
available languages.
### Accept-Charset Negotiation
```js
availableCharsets = ['utf-8', 'iso-8859-1', 'iso-8859-5']
negotiator = new Negotiator(request)
// Let's say Accept-Charset header is 'utf-8, iso-8859-1;q=0.8, utf-7;q=0.2'
negotiator.charsets()
// -> ['utf-8', 'iso-8859-1', 'utf-7']
negotiator.charsets(availableCharsets)
// -> ['utf-8', 'iso-8859-1']
negotiator.charset(availableCharsets)
// -> 'utf-8'
```
You can check a working example at `examples/charset.js`.
#### Methods
##### charset()
Returns the most preferred charset from the client.
##### charset(availableCharsets)
Returns the most preferred charset from a list of available charsets.
##### charsets()
Returns an array of preferred charsets ordered by the client preference.
##### charsets(availableCharsets)
Returns an array of preferred charsets ordered by priority from a list of
available charsets.
### Accept-Encoding Negotiation
```js
availableEncodings = ['identity', 'gzip']
negotiator = new Negotiator(request)
// Let's say Accept-Encoding header is 'gzip, compress;q=0.2, identity;q=0.5'
negotiator.encodings()
// -> ['gzip', 'identity', 'compress']
negotiator.encodings(availableEncodings)
// -> ['gzip', 'identity']
negotiator.encoding(availableEncodings)
// -> 'gzip'
```
You can check a working example at `examples/encoding.js`.
#### Methods
##### encoding()
Returns the most preferred encoding from the client.
##### encoding(availableEncodings)
Returns the most preferred encoding from a list of available encodings.
##### encodings()
Returns an array of preferred encodings ordered by the client preference.
##### encodings(availableEncodings)
Returns an array of preferred encodings ordered by priority from a list of
available encodings.
## See Also
The [accepts](https://npmjs.org/package/accepts#readme) module builds on
this module and provides an alternative interface, mime type validation,
and more.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/negotiator.svg
[npm-url]: https://npmjs.org/package/negotiator
[node-version-image]: https://img.shields.io/node/v/negotiator.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/negotiator/master.svg
[travis-url]: https://travis-ci.org/jshttp/negotiator
[coveralls-image]: https://img.shields.io/coveralls/jshttp/negotiator/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/negotiator?branch=master
[downloads-image]: https://img.shields.io/npm/dm/negotiator.svg
[downloads-url]: https://npmjs.org/package/negotiator
@@ -0,0 +1,62 @@
var preferredCharsets = require('./lib/charset');
var preferredEncodings = require('./lib/encoding');
var preferredLanguages = require('./lib/language');
var preferredMediaTypes = require('./lib/mediaType');
module.exports = Negotiator;
Negotiator.Negotiator = Negotiator;
function Negotiator(request) {
if (!(this instanceof Negotiator)) {
return new Negotiator(request);
}
this.request = request;
}
Negotiator.prototype.charset = function charset(available) {
var set = this.charsets(available);
return set && set[0];
};
Negotiator.prototype.charsets = function charsets(available) {
return preferredCharsets(this.request.headers['accept-charset'], available);
};
Negotiator.prototype.encoding = function encoding(available) {
var set = this.encodings(available);
return set && set[0];
};
Negotiator.prototype.encodings = function encodings(available) {
return preferredEncodings(this.request.headers['accept-encoding'], available);
};
Negotiator.prototype.language = function language(available) {
var set = this.languages(available);
return set && set[0];
};
Negotiator.prototype.languages = function languages(available) {
return preferredLanguages(this.request.headers['accept-language'], available);
};
Negotiator.prototype.mediaType = function mediaType(available) {
var set = this.mediaTypes(available);
return set && set[0];
};
Negotiator.prototype.mediaTypes = function mediaTypes(available) {
return preferredMediaTypes(this.request.headers.accept, available);
};
// Backwards compatibility
Negotiator.prototype.preferredCharset = Negotiator.prototype.charset;
Negotiator.prototype.preferredCharsets = Negotiator.prototype.charsets;
Negotiator.prototype.preferredEncoding = Negotiator.prototype.encoding;
Negotiator.prototype.preferredEncodings = Negotiator.prototype.encodings;
Negotiator.prototype.preferredLanguage = Negotiator.prototype.language;
Negotiator.prototype.preferredLanguages = Negotiator.prototype.languages;
Negotiator.prototype.preferredMediaType = Negotiator.prototype.mediaType;
Negotiator.prototype.preferredMediaTypes = Negotiator.prototype.mediaTypes;
@@ -0,0 +1,102 @@
module.exports = preferredCharsets;
preferredCharsets.preferredCharsets = preferredCharsets;
function parseAcceptCharset(accept) {
var accepts = accept.split(',');
for (var i = 0, j = 0; i < accepts.length; i++) {
var charset = parseCharset(accepts[i].trim(), i);
if (charset) {
accepts[j++] = charset;
}
}
// trim accepts
accepts.length = j;
return accepts;
}
function parseCharset(s, i) {
var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/);
if (!match) return null;
var charset = match[1];
var q = 1;
if (match[2]) {
var params = match[2].split(';')
for (var i = 0; i < params.length; i ++) {
var p = params[i].trim().split('=');
if (p[0] === 'q') {
q = parseFloat(p[1]);
break;
}
}
}
return {
charset: charset,
q: q,
i: i
};
}
function getCharsetPriority(charset, accepted, index) {
var priority = {o: -1, q: 0, s: 0};
for (var i = 0; i < accepted.length; i++) {
var spec = specify(charset, accepted[i], index);
if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
priority = spec;
}
}
return priority;
}
function specify(charset, spec, index) {
var s = 0;
if(spec.charset.toLowerCase() === charset.toLowerCase()){
s |= 1;
} else if (spec.charset !== '*' ) {
return null
}
return {
i: index,
o: spec.i,
q: spec.q,
s: s
}
}
function preferredCharsets(accept, provided) {
// RFC 2616 sec 14.2: no header = *
var accepts = parseAcceptCharset(accept === undefined ? '*' : accept || '');
if (!provided) {
// sorted list of all charsets
return accepts.filter(isQuality).sort(compareSpecs).map(function getCharset(spec) {
return spec.charset;
});
}
var priorities = provided.map(function getPriority(type, index) {
return getCharsetPriority(type, accepts, index);
});
// sorted list of accepted charsets
return priorities.filter(isQuality).sort(compareSpecs).map(function getCharset(priority) {
return provided[priorities.indexOf(priority)];
});
}
function compareSpecs(a, b) {
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
}
function isQuality(spec) {
return spec.q > 0;
}
@@ -0,0 +1,118 @@
module.exports = preferredEncodings;
preferredEncodings.preferredEncodings = preferredEncodings;
function parseAcceptEncoding(accept) {
var accepts = accept.split(',');
var hasIdentity = false;
var minQuality = 1;
for (var i = 0, j = 0; i < accepts.length; i++) {
var encoding = parseEncoding(accepts[i].trim(), i);
if (encoding) {
accepts[j++] = encoding;
hasIdentity = hasIdentity || specify('identity', encoding);
minQuality = Math.min(minQuality, encoding.q || 1);
}
}
if (!hasIdentity) {
/*
* If identity doesn't explicitly appear in the accept-encoding header,
* it's added to the list of acceptable encoding with the lowest q
*/
accepts[j++] = {
encoding: 'identity',
q: minQuality,
i: i
};
}
// trim accepts
accepts.length = j;
return accepts;
}
function parseEncoding(s, i) {
var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/);
if (!match) return null;
var encoding = match[1];
var q = 1;
if (match[2]) {
var params = match[2].split(';');
for (var i = 0; i < params.length; i ++) {
var p = params[i].trim().split('=');
if (p[0] === 'q') {
q = parseFloat(p[1]);
break;
}
}
}
return {
encoding: encoding,
q: q,
i: i
};
}
function getEncodingPriority(encoding, accepted, index) {
var priority = {o: -1, q: 0, s: 0};
for (var i = 0; i < accepted.length; i++) {
var spec = specify(encoding, accepted[i], index);
if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
priority = spec;
}
}
return priority;
}
function specify(encoding, spec, index) {
var s = 0;
if(spec.encoding.toLowerCase() === encoding.toLowerCase()){
s |= 1;
} else if (spec.encoding !== '*' ) {
return null
}
return {
i: index,
o: spec.i,
q: spec.q,
s: s
}
};
function preferredEncodings(accept, provided) {
var accepts = parseAcceptEncoding(accept || '');
if (!provided) {
// sorted list of all encodings
return accepts.filter(isQuality).sort(compareSpecs).map(function getEncoding(spec) {
return spec.encoding;
});
}
var priorities = provided.map(function getPriority(type, index) {
return getEncodingPriority(type, accepts, index);
});
// sorted list of accepted encodings
return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) {
return provided[priorities.indexOf(priority)];
});
}
function compareSpecs(a, b) {
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
}
function isQuality(spec) {
return spec.q > 0;
}
@@ -0,0 +1,112 @@
module.exports = preferredLanguages;
preferredLanguages.preferredLanguages = preferredLanguages;
function parseAcceptLanguage(accept) {
var accepts = accept.split(',');
for (var i = 0, j = 0; i < accepts.length; i++) {
var langauge = parseLanguage(accepts[i].trim(), i);
if (langauge) {
accepts[j++] = langauge;
}
}
// trim accepts
accepts.length = j;
return accepts;
}
function parseLanguage(s, i) {
var match = s.match(/^\s*(\S+?)(?:-(\S+?))?\s*(?:;(.*))?$/);
if (!match) return null;
var prefix = match[1],
suffix = match[2],
full = prefix;
if (suffix) full += "-" + suffix;
var q = 1;
if (match[3]) {
var params = match[3].split(';')
for (var i = 0; i < params.length; i ++) {
var p = params[i].split('=');
if (p[0] === 'q') q = parseFloat(p[1]);
}
}
return {
prefix: prefix,
suffix: suffix,
q: q,
i: i,
full: full
};
}
function getLanguagePriority(language, accepted, index) {
var priority = {o: -1, q: 0, s: 0};
for (var i = 0; i < accepted.length; i++) {
var spec = specify(language, accepted[i], index);
if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
priority = spec;
}
}
return priority;
}
function specify(language, spec, index) {
var p = parseLanguage(language)
if (!p) return null;
var s = 0;
if(spec.full.toLowerCase() === p.full.toLowerCase()){
s |= 4;
} else if (spec.prefix.toLowerCase() === p.full.toLowerCase()) {
s |= 2;
} else if (spec.full.toLowerCase() === p.prefix.toLowerCase()) {
s |= 1;
} else if (spec.full !== '*' ) {
return null
}
return {
i: index,
o: spec.i,
q: spec.q,
s: s
}
};
function preferredLanguages(accept, provided) {
// RFC 2616 sec 14.4: no header = *
var accepts = parseAcceptLanguage(accept === undefined ? '*' : accept || '');
if (!provided) {
// sorted list of all languages
return accepts.filter(isQuality).sort(compareSpecs).map(function getLanguage(spec) {
return spec.full;
});
}
var priorities = provided.map(function getPriority(type, index) {
return getLanguagePriority(type, accepts, index);
});
// sorted list of accepted languages
return priorities.filter(isQuality).sort(compareSpecs).map(function getLanguage(priority) {
return provided[priorities.indexOf(priority)];
});
}
function compareSpecs(a, b) {
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
}
function isQuality(spec) {
return spec.q > 0;
}
@@ -0,0 +1,179 @@
/**
* negotiator
* Copyright(c) 2012 Isaac Z. Schlueter
* Copyright(c) 2014 Federico Romero
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
module.exports = preferredMediaTypes;
preferredMediaTypes.preferredMediaTypes = preferredMediaTypes;
function parseAccept(accept) {
var accepts = splitMediaTypes(accept);
for (var i = 0, j = 0; i < accepts.length; i++) {
var mediaType = parseMediaType(accepts[i].trim(), i);
if (mediaType) {
accepts[j++] = mediaType;
}
}
// trim accepts
accepts.length = j;
return accepts;
};
function parseMediaType(s, i) {
var match = s.match(/\s*(\S+?)\/([^;\s]+)\s*(?:;(.*))?/);
if (!match) return null;
var type = match[1],
subtype = match[2],
full = "" + type + "/" + subtype,
params = {},
q = 1;
if (match[3]) {
params = match[3].split(';').map(function(s) {
return s.trim().split('=');
}).reduce(function (set, p) {
var name = p[0].toLowerCase();
var value = p[1];
set[name] = value && value[0] === '"' && value[value.length - 1] === '"'
? value.substr(1, value.length - 2)
: value;
return set;
}, params);
if (params.q != null) {
q = parseFloat(params.q);
delete params.q;
}
}
return {
type: type,
subtype: subtype,
params: params,
q: q,
i: i,
full: full
};
}
function getMediaTypePriority(type, accepted, index) {
var priority = {o: -1, q: 0, s: 0};
for (var i = 0; i < accepted.length; i++) {
var spec = specify(type, accepted[i], index);
if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
priority = spec;
}
}
return priority;
}
function specify(type, spec, index) {
var p = parseMediaType(type);
var s = 0;
if (!p) {
return null;
}
if(spec.type.toLowerCase() == p.type.toLowerCase()) {
s |= 4
} else if(spec.type != '*') {
return null;
}
if(spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {
s |= 2
} else if(spec.subtype != '*') {
return null;
}
var keys = Object.keys(spec.params);
if (keys.length > 0) {
if (keys.every(function (k) {
return spec.params[k] == '*' || (spec.params[k] || '').toLowerCase() == (p.params[k] || '').toLowerCase();
})) {
s |= 1
} else {
return null
}
}
return {
i: index,
o: spec.i,
q: spec.q,
s: s,
}
}
function preferredMediaTypes(accept, provided) {
// RFC 2616 sec 14.2: no header = */*
var accepts = parseAccept(accept === undefined ? '*/*' : accept || '');
if (!provided) {
// sorted list of all types
return accepts.filter(isQuality).sort(compareSpecs).map(function getType(spec) {
return spec.full;
});
}
var priorities = provided.map(function getPriority(type, index) {
return getMediaTypePriority(type, accepts, index);
});
// sorted list of accepted types
return priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
return provided[priorities.indexOf(priority)];
});
}
function compareSpecs(a, b) {
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
}
function isQuality(spec) {
return spec.q > 0;
}
function quoteCount(string) {
var count = 0;
var index = 0;
while ((index = string.indexOf('"', index)) !== -1) {
count++;
index++;
}
return count;
}
function splitMediaTypes(accept) {
var accepts = accept.split(',');
for (var i = 1, j = 0; i < accepts.length; i++) {
if (quoteCount(accepts[j]) % 2 == 0) {
accepts[++j] = accepts[i];
} else {
accepts[j] += ',' + accepts[i];
}
}
// trim accepts
accepts.length = j + 1;
return accepts;
}
File diff suppressed because one or more lines are too long
+60
View File
@@ -0,0 +1,60 @@
{
"name": "accepts",
"description": "Higher-level content negotiation",
"version": "1.2.13",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/jshttp/accepts"
},
"dependencies": {
"mime-types": "~2.1.6",
"negotiator": "0.5.3"
},
"devDependencies": {
"istanbul": "0.3.19",
"mocha": "~1.21.5"
},
"files": [
"LICENSE",
"HISTORY.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --check-leaks --bail 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/"
},
"keywords": [
"content",
"negotiation",
"accept",
"accepts"
],
"readme": "# accepts\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nHigher level content negotiation based on [negotiator](https://www.npmjs.com/package/negotiator). Extracted from [koa](https://www.npmjs.com/package/koa) for general use.\n\nIn addition to negotiator, it allows:\n\n- Allows types as an array or arguments list, ie `(['text/html', 'application/json'])` as well as `('text/html', 'application/json')`.\n- Allows type shorthands such as `json`.\n- Returns `false` when no types match\n- Treats non-existent headers as `*`\n\n## Installation\n\n```sh\nnpm install accepts\n```\n\n## API\n\n```js\nvar accepts = require('accepts')\n```\n\n### accepts(req)\n\nCreate a new `Accepts` object for the given `req`.\n\n#### .charset(charsets)\n\nReturn the first accepted charset. If nothing in `charsets` is accepted,\nthen `false` is returned.\n\n#### .charsets()\n\nReturn the charsets that the request accepts, in the order of the client's\npreference (most preferred first).\n\n#### .encoding(encodings)\n\nReturn the first accepted encoding. If nothing in `encodings` is accepted,\nthen `false` is returned.\n\n#### .encodings()\n\nReturn the encodings that the request accepts, in the order of the client's\npreference (most preferred first).\n\n#### .language(languages)\n\nReturn the first accepted language. If nothing in `languages` is accepted,\nthen `false` is returned.\n\n#### .languages()\n\nReturn the languages that the request accepts, in the order of the client's\npreference (most preferred first).\n\n#### .type(types)\n\nReturn the first accepted type (and it is returned as the same text as what\nappears in the `types` array). If nothing in `types` is accepted, then `false`\nis returned.\n\nThe `types` array can contain full MIME types or file extensions. Any value\nthat is not a full MIME types is passed to `require('mime-types').lookup`.\n\n#### .types()\n\nReturn the types that the request accepts, in the order of the client's\npreference (most preferred first).\n\n## Examples\n\n### Simple type negotiation\n\nThis simple example shows how to use `accepts` to return a different typed\nrespond body based on what the client wants to accept. The server lists it's\npreferences in order and will get back the best match between the client and\nserver.\n\n```js\nvar accepts = require('accepts')\nvar http = require('http')\n\nfunction app(req, res) {\n var accept = accepts(req)\n\n // the order of this list is significant; should be server preferred order\n switch(accept.type(['json', 'html'])) {\n case 'json':\n res.setHeader('Content-Type', 'application/json')\n res.write('{\"hello\":\"world!\"}')\n break\n case 'html':\n res.setHeader('Content-Type', 'text/html')\n res.write('<b>hello, world!</b>')\n break\n default:\n // the fallback is text/plain, so no need to specify it above\n res.setHeader('Content-Type', 'text/plain')\n res.write('hello, world!')\n break\n }\n\n res.end()\n}\n\nhttp.createServer(app).listen(3000)\n```\n\nYou can test this out with the cURL program:\n```sh\ncurl -I -H'Accept: text/html' http://localhost:3000/\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/accepts.svg\n[npm-url]: https://npmjs.org/package/accepts\n[node-version-image]: https://img.shields.io/node/v/accepts.svg\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/accepts/master.svg\n[travis-url]: https://travis-ci.org/jshttp/accepts\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/accepts/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/accepts\n[downloads-image]: https://img.shields.io/npm/dm/accepts.svg\n[downloads-url]: https://npmjs.org/package/accepts\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/accepts/issues"
},
"homepage": "https://github.com/jshttp/accepts",
"_id": "accepts@1.2.13",
"dist": {
"shasum": "d7247ef13389dfda2af55975c55fbc5c1119ade0"
},
"_from": "accepts@~1.2.12",
"_resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz"
}
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Blake Embrey (hello@blakeembrey.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.
+43
View File
@@ -0,0 +1,43 @@
# Array Flatten
[![NPM version][npm-image]][npm-url]
[![NPM downloads][downloads-image]][downloads-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
> Flatten an array of nested arrays into a single flat array. Accepts an optional depth.
## Installation
```
npm install array-flatten --save
```
## Usage
```javascript
var flatten = require('array-flatten')
flatten([1, [2, [3, [4, [5], 6], 7], 8], 9])
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
flatten([1, [2, [3, [4, [5], 6], 7], 8], 9], 2)
//=> [1, 2, 3, [4, [5], 6], 7, 8, 9]
(function () {
flatten(arguments) //=> [1, 2, 3]
})(1, [2, 3])
```
## License
MIT
[npm-image]: https://img.shields.io/npm/v/array-flatten.svg?style=flat
[npm-url]: https://npmjs.org/package/array-flatten
[downloads-image]: https://img.shields.io/npm/dm/array-flatten.svg?style=flat
[downloads-url]: https://npmjs.org/package/array-flatten
[travis-image]: https://img.shields.io/travis/blakeembrey/array-flatten.svg?style=flat
[travis-url]: https://travis-ci.org/blakeembrey/array-flatten
[coveralls-image]: https://img.shields.io/coveralls/blakeembrey/array-flatten.svg?style=flat
[coveralls-url]: https://coveralls.io/r/blakeembrey/array-flatten?branch=master
@@ -0,0 +1,64 @@
'use strict'
/**
* Expose `arrayFlatten`.
*/
module.exports = arrayFlatten
/**
* Recursive flatten function with depth.
*
* @param {Array} array
* @param {Array} result
* @param {Number} depth
* @return {Array}
*/
function flattenWithDepth (array, result, depth) {
for (var i = 0; i < array.length; i++) {
var value = array[i]
if (depth > 0 && Array.isArray(value)) {
flattenWithDepth(value, result, depth - 1)
} else {
result.push(value)
}
}
return result
}
/**
* Recursive flatten function. Omitting depth is slightly faster.
*
* @param {Array} array
* @param {Array} result
* @return {Array}
*/
function flattenForever (array, result) {
for (var i = 0; i < array.length; i++) {
var value = array[i]
if (Array.isArray(value)) {
flattenForever(value, result)
} else {
result.push(value)
}
}
return result
}
/**
* Flatten an array, with the ability to define a depth.
*
* @param {Array} array
* @param {Number} depth
* @return {Array}
*/
function arrayFlatten (array, depth) {
if (depth == null) {
return flattenForever(array, [])
}
return flattenWithDepth(array, [], depth)
}
@@ -0,0 +1,47 @@
{
"name": "array-flatten",
"version": "1.1.1",
"description": "Flatten an array of nested arrays into a single flat array",
"main": "array-flatten.js",
"files": [
"array-flatten.js",
"LICENSE"
],
"scripts": {
"test": "istanbul cover _mocha -- -R spec"
},
"repository": {
"type": "git",
"url": "git://github.com/blakeembrey/array-flatten.git"
},
"keywords": [
"array",
"flatten",
"arguments",
"depth"
],
"author": {
"name": "Blake Embrey",
"email": "hello@blakeembrey.com",
"url": "http://blakeembrey.me"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/blakeembrey/array-flatten/issues"
},
"homepage": "https://github.com/blakeembrey/array-flatten",
"devDependencies": {
"istanbul": "^0.3.13",
"mocha": "^2.2.4",
"pre-commit": "^1.0.7",
"standard": "^3.7.3"
},
"readme": "# Array Flatten\n\n[![NPM version][npm-image]][npm-url]\n[![NPM downloads][downloads-image]][downloads-url]\n[![Build status][travis-image]][travis-url]\n[![Test coverage][coveralls-image]][coveralls-url]\n\n> Flatten an array of nested arrays into a single flat array. Accepts an optional depth.\n\n## Installation\n\n```\nnpm install array-flatten --save\n```\n\n## Usage\n\n```javascript\nvar flatten = require('array-flatten')\n\nflatten([1, [2, [3, [4, [5], 6], 7], 8], 9])\n//=> [1, 2, 3, 4, 5, 6, 7, 8, 9]\n\nflatten([1, [2, [3, [4, [5], 6], 7], 8], 9], 2)\n//=> [1, 2, 3, [4, [5], 6], 7, 8, 9]\n\n(function () {\n flatten(arguments) //=> [1, 2, 3]\n})(1, [2, 3])\n```\n\n## License\n\nMIT\n\n[npm-image]: https://img.shields.io/npm/v/array-flatten.svg?style=flat\n[npm-url]: https://npmjs.org/package/array-flatten\n[downloads-image]: https://img.shields.io/npm/dm/array-flatten.svg?style=flat\n[downloads-url]: https://npmjs.org/package/array-flatten\n[travis-image]: https://img.shields.io/travis/blakeembrey/array-flatten.svg?style=flat\n[travis-url]: https://travis-ci.org/blakeembrey/array-flatten\n[coveralls-image]: https://img.shields.io/coveralls/blakeembrey/array-flatten.svg?style=flat\n[coveralls-url]: https://coveralls.io/r/blakeembrey/array-flatten?branch=master\n",
"readmeFilename": "README.md",
"_id": "array-flatten@1.1.1",
"dist": {
"shasum": "9a5f699051b1e7073328f2a008968b64ea2955d2"
},
"_from": "array-flatten@1.1.1",
"_resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
}
@@ -0,0 +1,40 @@
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
@@ -0,0 +1,22 @@
(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.
@@ -0,0 +1,141 @@
# 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
@@ -0,0 +1,443 @@
/*!
* 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
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
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`
+22
View File
@@ -0,0 +1,22 @@
(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.
+92
View File
@@ -0,0 +1,92 @@
# 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
+214
View File
@@ -0,0 +1,214 @@
/*!
* 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
}
@@ -0,0 +1,51 @@
{
"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": "git://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/"
},
"readme": "# content-type\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nCreate and parse HTTP Content-Type header according to RFC 7231\n\n## Installation\n\n```sh\n$ npm install content-type\n```\n\n## API\n\n```js\nvar contentType = require('content-type')\n```\n\n### contentType.parse(string)\n\n```js\nvar obj = contentType.parse('image/svg+xml; charset=utf-8')\n```\n\nParse a content type string. This will return an object with the following\nproperties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):\n\n - `type`: The media type (the type and subtype, always lower case).\n Example: `'image/svg+xml'`\n\n - `parameters`: An object of the parameters in the media type (name of parameter\n always lower case). Example: `{charset: 'utf-8'}`\n\nThrows a `TypeError` if the string is missing or invalid.\n\n### contentType.parse(req)\n\n```js\nvar obj = contentType.parse(req)\n```\n\nParse the `content-type` header from the given `req`. Short-cut for\n`contentType.parse(req.headers['content-type'])`.\n\nThrows a `TypeError` if the `Content-Type` header is missing or invalid.\n\n### contentType.parse(res)\n\n```js\nvar obj = contentType.parse(res)\n```\n\nParse the `content-type` header set on the given `res`. Short-cut for\n`contentType.parse(res.getHeader('content-type'))`.\n\nThrows a `TypeError` if the `Content-Type` header is missing or invalid.\n\n### contentType.format(obj)\n\n```js\nvar str = contentType.format({type: 'image/svg+xml'})\n```\n\nFormat an object into a content type string. This will return a string of the\ncontent type for the given object with the following properties (examples are\nshown that produce the string `'image/svg+xml; charset=utf-8'`):\n\n - `type`: The media type (will be lower-cased). Example: `'image/svg+xml'`\n\n - `parameters`: An object of the parameters in the media type (name of the\n parameter will be lower-cased). Example: `{charset: 'utf-8'}`\n\nThrows a `TypeError` if the object contains an invalid type or parameter names.\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/content-type.svg\n[npm-url]: https://npmjs.org/package/content-type\n[node-version-image]: https://img.shields.io/node/v/content-type.svg\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/content-type/master.svg\n[travis-url]: https://travis-ci.org/jshttp/content-type\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-type/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/content-type\n[downloads-image]: https://img.shields.io/npm/dm/content-type.svg\n[downloads-url]: https://npmjs.org/package/content-type\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/content-type/issues"
},
"homepage": "https://github.com/jshttp/content-type",
"_id": "content-type@1.0.1",
"dist": {
"shasum": "8005890c14fa93fad360838f7f23731efbd13974"
},
"_from": "content-type@~1.0.1",
"_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz"
}
@@ -0,0 +1,4 @@
support
test
examples
*.sock
@@ -0,0 +1,38 @@
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
@@ -0,0 +1,42 @@
# 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.
@@ -0,0 +1,51 @@
/**
* 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');
}
@@ -0,0 +1,40 @@
{
"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",
"readme": "\n# cookie-signature\n\n Sign and unsign cookies.\n\n## Example\n\n```js\nvar cookie = require('cookie-signature');\n\nvar val = cookie.sign('hello', 'tobiiscool');\nval.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');\n\nvar val = cookie.sign('hello', 'tobiiscool');\ncookie.unsign(val, 'tobiiscool').should.equal('hello');\ncookie.unsign(val, 'luna').should.be.false;\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 LearnBoost &lt;tj@learnboost.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/visionmedia/node-cookie-signature/issues"
},
"homepage": "https://github.com/visionmedia/node-cookie-signature",
"_id": "cookie-signature@1.0.6",
"dist": {
"shasum": "e303a882b342cc3ee8ca513a79999734dab3ae2c"
},
"_from": "cookie-signature@1.0.6",
"_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
}
+23
View File
@@ -0,0 +1,23 @@
(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.
+64
View File
@@ -0,0 +1,64 @@
# 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
+116
View File
@@ -0,0 +1,116 @@
/*!
* 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;
}
}
+47
View File
@@ -0,0 +1,47 @@
{
"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": "git://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/"
},
"readme": "# cookie\r\n\r\n[![NPM Version][npm-image]][npm-url]\r\n[![NPM Downloads][downloads-image]][downloads-url]\r\n[![Node.js Version][node-version-image]][node-version-url]\r\n[![Build Status][travis-image]][travis-url]\r\n[![Test Coverage][coveralls-image]][coveralls-url]\r\n\r\ncookie 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.\r\n\r\nSee [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.\r\n\r\n## how?\r\n\r\n```\r\nnpm install cookie\r\n```\r\n\r\n```javascript\r\nvar cookie = require('cookie');\r\n\r\nvar hdr = cookie.serialize('foo', 'bar');\r\n// hdr = 'foo=bar';\r\n\r\nvar cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');\r\n// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };\r\n```\r\n\r\n## more\r\n\r\nThe serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.\r\n\r\n### path\r\n> cookie path\r\n\r\n### expires\r\n> absolute expiration date for the cookie (Date object)\r\n\r\n### maxAge\r\n> relative max age of the cookie from when the client receives it (seconds)\r\n\r\n### domain\r\n> domain for the cookie\r\n\r\n### secure\r\n> true or false\r\n\r\n### httpOnly\r\n> true or false\r\n\r\n## License\r\n\r\n[MIT](LICENSE)\r\n\r\n[npm-image]: https://img.shields.io/npm/v/cookie.svg\r\n[npm-url]: https://npmjs.org/package/cookie\r\n[node-version-image]: https://img.shields.io/node/v/cookie.svg\r\n[node-version-url]: http://nodejs.org/download/\r\n[travis-image]: https://img.shields.io/travis/jshttp/cookie/master.svg\r\n[travis-url]: https://travis-ci.org/jshttp/cookie\r\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/cookie/master.svg\r\n[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master\r\n[downloads-image]: https://img.shields.io/npm/dm/cookie.svg\r\n[downloads-url]: https://npmjs.org/package/cookie\r\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/cookie/issues"
},
"homepage": "https://github.com/jshttp/cookie",
"_id": "cookie@0.1.3",
"dist": {
"shasum": "603399591fe1920213bab8ce2569b47e61c4c520"
},
"_from": "cookie@0.1.3",
"_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
}
+75
View File
@@ -0,0 +1,75 @@
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
+22
View File
@@ -0,0 +1,22 @@
(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.
+274
View File
@@ -0,0 +1,274 @@
# 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/
+529
View File
@@ -0,0 +1,529 @@
/*!
* 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
}
@@ -0,0 +1,33 @@
/*!
* 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
}
@@ -0,0 +1,101 @@
/*!
* 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
}
@@ -0,0 +1,69 @@
/*!
* 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()
}
File diff suppressed because one or more lines are too long
+22
View File
@@ -0,0 +1,22 @@
(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.
+15
View File
@@ -0,0 +1,15 @@
# escape-html
Escape HTML entities
## Example
```js
var escape = require('escape-html');
escape(str);
```
## License
MIT
+29
View File
@@ -0,0 +1,29 @@
/*!
* 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;');
}
@@ -0,0 +1,32 @@
{
"name": "escape-html",
"description": "Escape HTML entities",
"version": "1.0.2",
"license": "MIT",
"keywords": [
"escape",
"html",
"utility"
],
"repository": {
"type": "git",
"url": "git://github.com/component/escape-html"
},
"files": [
"LICENSE",
"Readme.md",
"index.js"
],
"readme": "\n# escape-html\n\n Escape HTML entities\n\n## Example\n\n```js\nvar escape = require('escape-html');\nescape(str);\n```\n\n## License\n\n MIT",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/component/escape-html/issues"
},
"homepage": "https://github.com/component/escape-html",
"_id": "escape-html@1.0.2",
"dist": {
"shasum": "f85ad082831d447455d1067256bb4dde592b0f6f"
},
"_from": "escape-html@1.0.2",
"_resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz"
}
+71
View File
@@ -0,0 +1,71 @@
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
+22
View File
@@ -0,0 +1,22 @@
(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.
+165
View File
@@ -0,0 +1,165 @@
# 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
+132
View File
@@ -0,0 +1,132 @@
/*!
* 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 + '"'
}
+59
View File
@@ -0,0 +1,59 @@
{
"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": "git://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/"
},
"readme": "# etag\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nCreate simple ETags\n\n## Installation\n\n```sh\n$ npm install etag\n```\n\n## API\n\n```js\nvar etag = require('etag')\n```\n\n### etag(entity, [options])\n\nGenerate a strong ETag for the given entity. This should be the complete\nbody of the entity. Strings, `Buffer`s, and `fs.Stats` are accepted. By\ndefault, a strong ETag is generated except for `fs.Stats`, which will\ngenerate a weak ETag (this can be overwritten by `options.weak`).\n\n```js\nres.setHeader('ETag', etag(body))\n```\n\n#### Options\n\n`etag` accepts these properties in the options object.\n\n##### weak\n\nSpecifies if the generated ETag will include the weak validator mark (that\nis, the leading `W/`). The actual entity tag is the same. The default value\nis `false`, unless the `entity` is `fs.Stats`, in which case it is `true`.\n\n## Testing\n\n```sh\n$ npm test\n```\n\n## Benchmark\n\n```bash\n$ npm run-script bench\n\n> etag@1.6.0 bench nodejs-etag\n> node benchmark/index.js\n\n http_parser@1.0\n node@0.10.33\n v8@3.14.5.9\n ares@1.9.0-DEV\n uv@0.10.29\n zlib@1.2.3\n modules@11\n openssl@1.0.1j\n\n> node benchmark/body0-100b.js\n\n 100B body\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* buffer - strong x 289,198 ops/sec ±1.09% (190 runs sampled)\n* buffer - weak x 287,838 ops/sec ±0.91% (189 runs sampled)\n* string - strong x 284,586 ops/sec ±1.05% (192 runs sampled)\n* string - weak x 287,439 ops/sec ±0.82% (192 runs sampled)\n\n> node benchmark/body1-1kb.js\n\n 1KB body\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* buffer - strong x 212,423 ops/sec ±0.75% (193 runs sampled)\n* buffer - weak x 211,871 ops/sec ±0.74% (194 runs sampled)\n string - strong x 205,291 ops/sec ±0.86% (194 runs sampled)\n string - weak x 208,463 ops/sec ±0.79% (192 runs sampled)\n\n> node benchmark/body2-5kb.js\n\n 5KB body\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* buffer - strong x 92,901 ops/sec ±0.58% (195 runs sampled)\n* buffer - weak x 93,045 ops/sec ±0.65% (192 runs sampled)\n string - strong x 89,621 ops/sec ±0.68% (194 runs sampled)\n string - weak x 90,070 ops/sec ±0.70% (196 runs sampled)\n\n> node benchmark/body3-10kb.js\n\n 10KB body\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* buffer - strong x 54,220 ops/sec ±0.85% (192 runs sampled)\n* buffer - weak x 54,069 ops/sec ±0.83% (191 runs sampled)\n string - strong x 53,078 ops/sec ±0.53% (194 runs sampled)\n string - weak x 53,849 ops/sec ±0.47% (197 runs sampled)\n\n> node benchmark/body4-100kb.js\n\n 100KB body\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* buffer - strong x 6,673 ops/sec ±0.15% (197 runs sampled)\n* buffer - weak x 6,716 ops/sec ±0.12% (198 runs sampled)\n string - strong x 6,357 ops/sec ±0.14% (197 runs sampled)\n string - weak x 6,344 ops/sec ±0.21% (197 runs sampled)\n\n> node benchmark/stats.js\n\n stats\n\n 1 test completed.\n 2 tests completed.\n 3 tests completed.\n 4 tests completed.\n\n* real - strong x 1,671,989 ops/sec ±0.13% (197 runs sampled)\n* real - weak x 1,681,297 ops/sec ±0.12% (198 runs sampled)\n fake - strong x 927,063 ops/sec ±0.14% (198 runs sampled)\n fake - weak x 914,461 ops/sec ±0.41% (191 runs sampled)\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/etag.svg\n[npm-url]: https://npmjs.org/package/etag\n[node-version-image]: https://img.shields.io/node/v/etag.svg\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/etag/master.svg\n[travis-url]: https://travis-ci.org/jshttp/etag\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/etag/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/etag?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/etag.svg\n[downloads-url]: https://npmjs.org/package/etag\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/etag/issues"
},
"homepage": "https://github.com/jshttp/etag",
"_id": "etag@1.7.0",
"dist": {
"shasum": "70fe2744c4b6d8bab6435666c787e15969c4575c"
},
"_from": "etag@~1.7.0",
"_resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz"
}
+90
View File
@@ -0,0 +1,90 @@
0.4.0 / 2015-06-14
==================
* 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
- Add defined behavior for HTTP `CONNECT` requests
- Add defined behavior for HTTP `Upgrade` requests
- deps: ee-first@1.1.1
* perf: enable strict mode
* perf: remove argument reassignment
0.3.6 / 2015-05-11
==================
* deps: debug@~2.2.0
- deps: ms@0.7.1
0.3.5 / 2015-04-22
==================
* deps: on-finished@~2.2.1
- Fix `isFinished(req)` when data buffered
0.3.4 / 2015-03-15
==================
* deps: debug@~2.1.3
- Fix high intensity foreground color for bold
- deps: ms@0.7.0
0.3.3 / 2015-01-01
==================
* deps: debug@~2.1.1
* deps: on-finished@~2.2.0
0.3.2 / 2014-10-22
==================
* deps: on-finished@~2.1.1
- Fix handling of pipelined requests
0.3.1 / 2014-10-16
==================
* deps: debug@~2.1.0
- Implement `DEBUG_FD` env variable support
0.3.0 / 2014-09-17
==================
* Terminate in progress response only on error
* Use `on-finished` to determine request status
0.2.0 / 2014-09-03
==================
* Set `X-Content-Type-Options: nosniff` header
* deps: debug@~2.0.0
0.1.0 / 2014-07-16
==================
* Respond after request fully read
- prevents hung responses and socket hang ups
* deps: debug@1.0.4
0.0.3 / 2014-07-11
==================
* deps: debug@1.0.3
- Add support for multiple wildcards in namespaces
0.0.2 / 2014-06-19
==================
* Handle invalid status codes
0.0.1 / 2014-06-05
==================
* deps: debug@1.0.2
0.0.0 / 2014-06-05
==================
* Extracted from connect/express
+22
View File
@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2014-2015 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.
+133
View File
@@ -0,0 +1,133 @@
# finalhandler
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Node.js function to invoke as the final step to respond to HTTP request.
## Installation
```sh
$ npm install finalhandler
```
## API
```js
var finalhandler = require('finalhandler')
```
### finalhandler(req, res, [options])
Returns function to be invoked as the final step for the given `req` and `res`.
This function is to be invoked as `fn(err)`. If `err` is falsy, the handler will
write out a 404 response to the `res`. If it is truthy, an error response will
be written out to the `res`, and `res.statusCode` is set from `err.status`.
The final handler will also unpipe anything from `req` when it is invoked.
#### options.env
By default, the environment is determined by `NODE_ENV` variable, but it can be
overridden by this option.
#### options.onerror
Provide a function to be called with the `err` when it exists. Can be used for
writing errors to a central location without excessive function generation. Called
as `onerror(err, req, res)`.
## Examples
### always 404
```js
var finalhandler = require('finalhandler')
var http = require('http')
var server = http.createServer(function (req, res) {
var done = finalhandler(req, res)
done()
})
server.listen(3000)
```
### perform simple action
```js
var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')
var server = http.createServer(function (req, res) {
var done = finalhandler(req, res)
fs.readFile('index.html', function (err, buf) {
if (err) return done(err)
res.setHeader('Content-Type', 'text/html')
res.end(buf)
})
})
server.listen(3000)
```
### use with middleware-style functions
```js
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')
var serve = serveStatic('public')
var server = http.createServer(function (req, res) {
var done = finalhandler(req, res)
serve(req, res, done)
})
server.listen(3000)
```
### keep log of all errors
```js
var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')
var server = http.createServer(function (req, res) {
var done = finalhandler(req, res, {onerror: logerror})
fs.readFile('index.html', function (err, buf) {
if (err) return done(err)
res.setHeader('Content-Type', 'text/html')
res.end(buf)
})
})
server.listen(3000)
function logerror(err) {
console.error(err.stack || err.toString())
}
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/finalhandler.svg
[npm-url]: https://npmjs.org/package/finalhandler
[node-image]: https://img.shields.io/node/v/finalhandler.svg
[node-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/pillarjs/finalhandler.svg
[travis-url]: https://travis-ci.org/pillarjs/finalhandler
[coveralls-image]: https://img.shields.io/coveralls/pillarjs/finalhandler.svg
[coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master
[downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg
[downloads-url]: https://npmjs.org/package/finalhandler
+151
View File
@@ -0,0 +1,151 @@
/*!
* finalhandler
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var debug = require('debug')('finalhandler')
var escapeHtml = require('escape-html')
var http = require('http')
var onFinished = require('on-finished')
var unpipe = require('unpipe')
/**
* Module variables.
* @private
*/
/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
? setImmediate
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
var isFinished = onFinished.isFinished
/**
* Module exports.
* @public
*/
module.exports = finalhandler
/**
* Create a function to handle the final response.
*
* @param {Request} req
* @param {Response} res
* @param {Object} [options]
* @return {Function}
* @public
*/
function finalhandler(req, res, options) {
var opts = options || {}
// get environment
var env = opts.env || process.env.NODE_ENV || 'development'
// get error callback
var onerror = opts.onerror
return function (err) {
var status = res.statusCode
// ignore 404 on in-flight response
if (!err && res._header) {
debug('cannot 404 after headers sent')
return
}
// unhandled error
if (err) {
// respect err.statusCode
if (err.statusCode) {
status = err.statusCode
}
// respect err.status
if (err.status) {
status = err.status
}
// default status code to 500
if (!status || status < 400) {
status = 500
}
// production gets a basic error message
var msg = env === 'production'
? http.STATUS_CODES[status]
: err.stack || err.toString()
msg = escapeHtml(msg)
.replace(/\n/g, '<br>')
.replace(/ /g, ' &nbsp;') + '\n'
} else {
status = 404
msg = 'Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl || req.url) + '\n'
}
debug('default %s', status)
// schedule onerror callback
if (err && onerror) {
defer(onerror, err, req, res)
}
// cannot actually respond
if (res._header) {
return req.socket.destroy()
}
send(req, res, status, msg)
}
}
/**
* Send response.
*
* @param {IncomingMessage} req
* @param {OutgoingMessage} res
* @param {number} status
* @param {string} body
* @private
*/
function send(req, res, status, body) {
function write() {
res.statusCode = status
// security header for content sniffing
res.setHeader('X-Content-Type-Options', 'nosniff')
// standard headers
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'))
if (req.method === 'HEAD') {
res.end()
return
}
res.end(body, 'utf8')
}
if (isFinished(req)) {
write()
return
}
// unpipe everything from the request
unpipe(req)
// flush the request
onFinished(req, write)
req.resume()
}
@@ -0,0 +1,4 @@
1.0.0 / 2015-06-14
==================
* Initial release
@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2015 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.
@@ -0,0 +1,43 @@
# unpipe
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Unpipe a stream from all destinations.
## Installation
```sh
$ npm install unpipe
```
## API
```js
var unpipe = require('unpipe')
```
### unpipe(stream)
Unpipes all destinations from a given stream. With stream 2+, this is
equivalent to `stream.unpipe()`. When used with streams 1 style streams
(typically Node.js 0.8 and below), this module attempts to undo the
actions done in `stream.pipe(dest)`.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/unpipe.svg
[npm-url]: https://npmjs.org/package/unpipe
[node-image]: https://img.shields.io/node/v/unpipe.svg
[node-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/stream-utils/unpipe.svg
[travis-url]: https://travis-ci.org/stream-utils/unpipe
[coveralls-image]: https://img.shields.io/coveralls/stream-utils/unpipe.svg
[coveralls-url]: https://coveralls.io/r/stream-utils/unpipe?branch=master
[downloads-image]: https://img.shields.io/npm/dm/unpipe.svg
[downloads-url]: https://npmjs.org/package/unpipe
@@ -0,0 +1,69 @@
/*!
* unpipe
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = unpipe
/**
* Determine if there are Node.js pipe-like data listeners.
* @private
*/
function hasPipeDataListeners(stream) {
var listeners = stream.listeners('data')
for (var i = 0; i < listeners.length; i++) {
if (listeners[i].name === 'ondata') {
return true
}
}
return false
}
/**
* Unpipe a stream from all destinations.
*
* @param {object} stream
* @public
*/
function unpipe(stream) {
if (!stream) {
throw new TypeError('argument stream is required')
}
if (typeof stream.unpipe === 'function') {
// new-style
stream.unpipe()
return
}
// Node.js 0.8 hack
if (!hasPipeDataListeners(stream)) {
return
}
var listener
var listeners = stream.listeners('close')
for (var i = 0; i < listeners.length; i++) {
listener = listeners[i]
if (listener.name !== 'cleanup' && listener.name !== 'onclose') {
continue
}
// invoke the listener
listener.call(stream)
}
}
@@ -0,0 +1,45 @@
{
"name": "unpipe",
"description": "Unpipe a stream from all destinations",
"version": "1.0.0",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/stream-utils/unpipe"
},
"devDependencies": {
"istanbul": "0.3.15",
"mocha": "2.2.5",
"readable-stream": "1.1.13"
},
"files": [
"HISTORY.md",
"LICENSE",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.8"
},
"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/"
},
"readme": "# unpipe\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-image]][node-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nUnpipe a stream from all destinations.\n\n## Installation\n\n```sh\n$ npm install unpipe\n```\n\n## API\n\n```js\nvar unpipe = require('unpipe')\n```\n\n### unpipe(stream)\n\nUnpipes all destinations from a given stream. With stream 2+, this is\nequivalent to `stream.unpipe()`. When used with streams 1 style streams\n(typically Node.js 0.8 and below), this module attempts to undo the\nactions done in `stream.pipe(dest)`.\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/unpipe.svg\n[npm-url]: https://npmjs.org/package/unpipe\n[node-image]: https://img.shields.io/node/v/unpipe.svg\n[node-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/stream-utils/unpipe.svg\n[travis-url]: https://travis-ci.org/stream-utils/unpipe\n[coveralls-image]: https://img.shields.io/coveralls/stream-utils/unpipe.svg\n[coveralls-url]: https://coveralls.io/r/stream-utils/unpipe?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/unpipe.svg\n[downloads-url]: https://npmjs.org/package/unpipe\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/stream-utils/unpipe/issues"
},
"homepage": "https://github.com/stream-utils/unpipe",
"_id": "unpipe@1.0.0",
"dist": {
"shasum": "1b8a41f659ae33694a894cf4abd8df3013b41034"
},
"_from": "unpipe@~1.0.0",
"_resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
}
@@ -0,0 +1,51 @@
{
"name": "finalhandler",
"description": "Node.js final http responder",
"version": "0.4.0",
"author": {
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/pillarjs/finalhandler"
},
"dependencies": {
"debug": "~2.2.0",
"escape-html": "1.0.2",
"on-finished": "~2.3.0",
"unpipe": "~1.0.0"
},
"devDependencies": {
"istanbul": "0.3.15",
"mocha": "2.2.5",
"readable-stream": "2.0.0",
"supertest": "1.0.1"
},
"files": [
"LICENSE",
"HISTORY.md",
"index.js"
],
"engines": {
"node": ">= 0.8"
},
"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/"
},
"readme": "# finalhandler\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-image]][node-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nNode.js function to invoke as the final step to respond to HTTP request.\n\n## Installation\n\n```sh\n$ npm install finalhandler\n```\n\n## API\n\n```js\nvar finalhandler = require('finalhandler')\n```\n\n### finalhandler(req, res, [options])\n\nReturns function to be invoked as the final step for the given `req` and `res`.\nThis function is to be invoked as `fn(err)`. If `err` is falsy, the handler will\nwrite out a 404 response to the `res`. If it is truthy, an error response will\nbe written out to the `res`, and `res.statusCode` is set from `err.status`.\n\nThe final handler will also unpipe anything from `req` when it is invoked.\n\n#### options.env\n\nBy default, the environment is determined by `NODE_ENV` variable, but it can be\noverridden by this option.\n\n#### options.onerror\n\nProvide a function to be called with the `err` when it exists. Can be used for\nwriting errors to a central location without excessive function generation. Called\nas `onerror(err, req, res)`.\n\n## Examples\n\n### always 404\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n var done = finalhandler(req, res)\n done()\n})\n\nserver.listen(3000)\n```\n\n### perform simple action\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n var done = finalhandler(req, res)\n\n fs.readFile('index.html', function (err, buf) {\n if (err) return done(err)\n res.setHeader('Content-Type', 'text/html')\n res.end(buf)\n })\n})\n\nserver.listen(3000)\n```\n\n### use with middleware-style functions\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\nvar serve = serveStatic('public')\n\nvar server = http.createServer(function (req, res) {\n var done = finalhandler(req, res)\n serve(req, res, done)\n})\n\nserver.listen(3000)\n```\n\n### keep log of all errors\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n var done = finalhandler(req, res, {onerror: logerror})\n\n fs.readFile('index.html', function (err, buf) {\n if (err) return done(err)\n res.setHeader('Content-Type', 'text/html')\n res.end(buf)\n })\n})\n\nserver.listen(3000)\n\nfunction logerror(err) {\n console.error(err.stack || err.toString())\n}\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/finalhandler.svg\n[npm-url]: https://npmjs.org/package/finalhandler\n[node-image]: https://img.shields.io/node/v/finalhandler.svg\n[node-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/pillarjs/finalhandler.svg\n[travis-url]: https://travis-ci.org/pillarjs/finalhandler\n[coveralls-image]: https://img.shields.io/coveralls/pillarjs/finalhandler.svg\n[coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg\n[downloads-url]: https://npmjs.org/package/finalhandler\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/pillarjs/finalhandler/issues"
},
"homepage": "https://github.com/pillarjs/finalhandler",
"_id": "finalhandler@0.4.0",
"dist": {
"shasum": "61d142a03dd1d92ddd824d1b2a3277c9f9ddf2b1"
},
"_from": "finalhandler@0.4.0",
"_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz"
}
+38
View File
@@ -0,0 +1,38 @@
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
+22
View File
@@ -0,0 +1,22 @@
(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.
+58
View File
@@ -0,0 +1,58 @@
# 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
+57
View File
@@ -0,0 +1,57 @@
/**
* 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);
}
+61
View File
@@ -0,0 +1,61 @@
{
"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": "git://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/"
},
"readme": "# fresh\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nHTTP response freshness testing\n\n## Installation\n\n```\n$ npm install fresh\n```\n\n## API\n\n```js\nvar fresh = require('fresh')\n```\n\n### fresh(req, res)\n\n Check freshness of `req` and `res` headers.\n\n When the cache is \"fresh\" __true__ is returned,\n otherwise __false__ is returned to indicate that\n the cache is now stale.\n\n## Example\n\n```js\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'luna' };\nfresh(req, res);\n// => false\n\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'tobi' };\nfresh(req, res);\n// => true\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/fresh.svg\n[npm-url]: https://npmjs.org/package/fresh\n[node-version-image]: https://img.shields.io/node/v/fresh.svg\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/fresh/master.svg\n[travis-url]: https://travis-ci.org/jshttp/fresh\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/fresh/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/fresh?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/fresh.svg\n[downloads-url]: https://npmjs.org/package/fresh\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/fresh/issues"
},
"homepage": "https://github.com/jshttp/fresh",
"_id": "fresh@0.3.0",
"dist": {
"shasum": "7dfb92da4a856c1e4ec57ee4145260ac8256a455"
},
"_from": "fresh@0.3.0",
"_resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz"
}
@@ -0,0 +1,22 @@
(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.
@@ -0,0 +1,34 @@
# 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)
@@ -0,0 +1,57 @@
/*!
* 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
}
@@ -0,0 +1,38 @@
{
"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"
],
"readme": "# Merge Descriptors\n\nMerge objects using descriptors.\n\n```js\nvar thing = {\n get name() {\n return 'jon'\n }\n}\n\nvar animal = {\n\n}\n\nmerge(animal, thing)\n\nanimal.name === 'jon'\n```\n\n## API\n\n### merge(destination, source)\n\nRedefines `destination`'s descriptors with `source`'s.\n\n### merge(destination, source, false)\n\nDefines `source`'s descriptors on `destination` if `destination` does not have\na descriptor by the same name.\n\n## License\n\n[MIT](LICENSE)\n",
"readmeFilename": "README.md",
"homepage": "https://github.com/component/merge-descriptors",
"_id": "merge-descriptors@1.0.0",
"dist": {
"shasum": "65a3f6275f385396843524bd88aded2d50cfd266"
},
"_from": "merge-descriptors@1.0.0",
"_resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz"
}
+24
View File
@@ -0,0 +1,24 @@
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
+23
View File
@@ -0,0 +1,23 @@
(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.
+41
View File
@@ -0,0 +1,41 @@
# 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
+42
View File
@@ -0,0 +1,42 @@
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'
];
}
+62
View File
@@ -0,0 +1,62 @@
{
"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": "git://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"
],
"readme": "# Methods\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\n HTTP verbs that node core's parser supports.\n\n\n## Install\n\n```bash\n$ npm install methods\n```\n\n## API\n\n```js\nvar methods = require('methods')\n```\n\n### methods\n\nThis is an array of lower-case method names that Node.js supports.\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/methods.svg?style=flat\n[npm-url]: https://npmjs.org/package/methods\n[node-version-image]: https://img.shields.io/node/v/methods.svg?style=flat\n[node-version-url]: http://nodejs.org/download/\n[travis-image]: https://img.shields.io/travis/jshttp/methods.svg?style=flat\n[travis-url]: https://travis-ci.org/jshttp/methods\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/methods.svg?style=flat\n[coveralls-url]: https://coveralls.io/r/jshttp/methods?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/methods.svg?style=flat\n[downloads-url]: https://npmjs.org/package/methods\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jshttp/methods/issues"
},
"homepage": "https://github.com/jshttp/methods",
"_id": "methods@1.1.1",
"dist": {
"shasum": "acc80716cdd3ecf21c671027be6447df214a60be"
},
"_from": "methods@~1.1.1",
"_resolved": "https://registry.npmjs.org/methods/-/methods-1.1.1.tgz"
}
+88
View File
@@ -0,0 +1,88 @@
2.3.0 / 2015-05-26
==================
* Add defined behavior for HTTP `CONNECT` requests
* Add defined behavior for HTTP `Upgrade` requests
* deps: ee-first@1.1.1
2.2.1 / 2015-04-22
==================
* Fix `isFinished(req)` when data buffered
2.2.0 / 2014-12-22
==================
* Add message object to callback arguments
2.1.1 / 2014-10-22
==================
* Fix handling of pipelined requests
2.1.0 / 2014-08-16
==================
* Check if `socket` is detached
* Return `undefined` for `isFinished` if state unknown
2.0.0 / 2014-08-16
==================
* Add `isFinished` function
* Move to `jshttp` organization
* Remove support for plain socket argument
* Rename to `on-finished`
* Support both `req` and `res` as arguments
* deps: ee-first@1.0.5
1.2.2 / 2014-06-10
==================
* Reduce listeners added to emitters
- avoids "event emitter leak" warnings when used multiple times on same request
1.2.1 / 2014-06-08
==================
* Fix returned value when already finished
1.2.0 / 2014-06-05
==================
* Call callback when called on already-finished socket
1.1.4 / 2014-05-27
==================
* Support node.js 0.8
1.1.3 / 2014-04-30
==================
* Make sure errors passed as instanceof `Error`
1.1.2 / 2014-04-18
==================
* Default the `socket` to passed-in object
1.1.1 / 2014-01-16
==================
* Rename module to `finished`
1.1.0 / 2013-12-25
==================
* Call callback when called on already-errored socket
1.0.1 / 2013-12-20
==================
* Actually pass the error to the callback
1.0.0 / 2013-12-20
==================
* Initial release
+23
View File
@@ -0,0 +1,23 @@
(The MIT License)
Copyright (c) 2013 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.
+154
View File
@@ -0,0 +1,154 @@
# on-finished
[![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]
Execute a callback when a HTTP request closes, finishes, or errors.
## Install
```sh
$ npm install on-finished
```
## API
```js
var onFinished = require('on-finished')
```
### onFinished(res, listener)
Attach a listener to listen for the response to finish. The listener will
be invoked only once when the response finished. If the response finished
to an error, the first argument will contain the error. If the response
has already finished, the listener will be invoked.
Listening to the end of a response would be used to close things associated
with the response, like open files.
Listener is invoked as `listener(err, res)`.
```js
onFinished(res, function (err, res) {
// clean up open fds, etc.
// err contains the error is request error'd
})
```
### onFinished(req, listener)
Attach a listener to listen for the request to finish. The listener will
be invoked only once when the request finished. If the request finished
to an error, the first argument will contain the error. If the request
has already finished, the listener will be invoked.
Listening to the end of a request would be used to know when to continue
after reading the data.
Listener is invoked as `listener(err, req)`.
```js
var data = ''
req.setEncoding('utf8')
res.on('data', function (str) {
data += str
})
onFinished(req, function (err, req) {
// data is read unless there is err
})
```
### onFinished.isFinished(res)
Determine if `res` is already finished. This would be useful to check and
not even start certain operations if the response has already finished.
### onFinished.isFinished(req)
Determine if `req` is already finished. This would be useful to check and
not even start certain operations if the request has already finished.
## Special Node.js requests
### HTTP CONNECT method
The meaning of the `CONNECT` method from RFC 7231, section 4.3.6:
> The CONNECT method requests that the recipient establish a tunnel to
> the destination origin server identified by the request-target and,
> if successful, thereafter restrict its behavior to blind forwarding
> of packets, in both directions, until the tunnel is closed. Tunnels
> are commonly used to create an end-to-end virtual connection, through
> one or more proxies, which can then be secured using TLS (Transport
> Layer Security, [RFC5246]).
In Node.js, these request objects come from the `'connect'` event on
the HTTP server.
When this module is used on a HTTP `CONNECT` request, the request is
considered "finished" immediately, **due to limitations in the Node.js
interface**. This means if the `CONNECT` request contains a request entity,
the request will be considered "finished" even before it has been read.
There is no such thing as a response object to a `CONNECT` request in
Node.js, so there is no support for for one.
### HTTP Upgrade request
The meaning of the `Upgrade` header from RFC 7230, section 6.1:
> The "Upgrade" header field is intended to provide a simple mechanism
> for transitioning from HTTP/1.1 to some other protocol on the same
> connection.
In Node.js, these request objects come from the `'upgrade'` event on
the HTTP server.
When this module is used on a HTTP request with an `Upgrade` header, the
request is considered "finished" immediately, **due to limitations in the
Node.js interface**. This means if the `Upgrade` request contains a request
entity, the request will be considered "finished" even before it has been
read.
There is no such thing as a response object to a `Upgrade` request in
Node.js, so there is no support for for one.
## Example
The following code ensures that file descriptors are always closed
once the response finishes.
```js
var destroy = require('destroy')
var http = require('http')
var onFinished = require('on-finished')
http.createServer(function onRequest(req, res) {
var stream = fs.createReadStream('package.json')
stream.pipe(res)
onFinished(res, function (err) {
destroy(stream)
})
})
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/on-finished.svg
[npm-url]: https://npmjs.org/package/on-finished
[node-version-image]: https://img.shields.io/node/v/on-finished.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/on-finished/master.svg
[travis-url]: https://travis-ci.org/jshttp/on-finished
[coveralls-image]: https://img.shields.io/coveralls/jshttp/on-finished/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/on-finished?branch=master
[downloads-image]: https://img.shields.io/npm/dm/on-finished.svg
[downloads-url]: https://npmjs.org/package/on-finished
+196
View File
@@ -0,0 +1,196 @@
/*!
* on-finished
* Copyright(c) 2013 Jonathan Ong
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = onFinished
module.exports.isFinished = isFinished
/**
* Module dependencies.
* @private
*/
var first = require('ee-first')
/**
* Variables.
* @private
*/
/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
? setImmediate
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
/**
* Invoke callback when the response has finished, useful for
* cleaning up resources afterwards.
*
* @param {object} msg
* @param {function} listener
* @return {object}
* @public
*/
function onFinished(msg, listener) {
if (isFinished(msg) !== false) {
defer(listener, null, msg)
return msg
}
// attach the listener to the message
attachListener(msg, listener)
return msg
}
/**
* Determine if message is already finished.
*
* @param {object} msg
* @return {boolean}
* @public
*/
function isFinished(msg) {
var socket = msg.socket
if (typeof msg.finished === 'boolean') {
// OutgoingMessage
return Boolean(msg.finished || (socket && !socket.writable))
}
if (typeof msg.complete === 'boolean') {
// IncomingMessage
return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
}
// don't know
return undefined
}
/**
* Attach a finished listener to the message.
*
* @param {object} msg
* @param {function} callback
* @private
*/
function attachFinishedListener(msg, callback) {
var eeMsg
var eeSocket
var finished = false
function onFinish(error) {
eeMsg.cancel()
eeSocket.cancel()
finished = true
callback(error)
}
// finished on first message event
eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
function onSocket(socket) {
// remove listener
msg.removeListener('socket', onSocket)
if (finished) return
if (eeMsg !== eeSocket) return
// finished on first socket event
eeSocket = first([[socket, 'error', 'close']], onFinish)
}
if (msg.socket) {
// socket already assigned
onSocket(msg.socket)
return
}
// wait for socket to be assigned
msg.on('socket', onSocket)
if (msg.socket === undefined) {
// node.js 0.8 patch
patchAssignSocket(msg, onSocket)
}
}
/**
* Attach the listener to the message.
*
* @param {object} msg
* @return {function}
* @private
*/
function attachListener(msg, listener) {
var attached = msg.__onFinished
// create a private single listener with queue
if (!attached || !attached.queue) {
attached = msg.__onFinished = createListener(msg)
attachFinishedListener(msg, attached)
}
attached.queue.push(listener)
}
/**
* Create listener on message.
*
* @param {object} msg
* @return {function}
* @private
*/
function createListener(msg) {
function listener(err) {
if (msg.__onFinished === listener) msg.__onFinished = null
if (!listener.queue) return
var queue = listener.queue
listener.queue = null
for (var i = 0; i < queue.length; i++) {
queue[i](err, msg)
}
}
listener.queue = []
return listener
}
/**
* Patch ServerResponse.prototype.assignSocket for node.js 0.8.
*
* @param {ServerResponse} res
* @param {function} callback
* @private
*/
function patchAssignSocket(res, callback) {
var assignSocket = res.assignSocket
if (typeof assignSocket !== 'function') return
// res.on('socket', callback) is broken in 0.8
res.assignSocket = function _assignSocket(socket) {
assignSocket.call(this, socket)
callback(socket)
}
}
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 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.
@@ -0,0 +1,80 @@
# EE First
[![NPM version][npm-image]][npm-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![Gittip][gittip-image]][gittip-url]
Get the first event in a set of event emitters and event pairs,
then clean up after itself.
## Install
```sh
$ npm install ee-first
```
## API
```js
var first = require('ee-first')
```
### first(arr, listener)
Invoke `listener` on the first event from the list specified in `arr`. `arr` is
an array of arrays, with each array in the format `[ee, ...event]`. `listener`
will be called only once, the first time any of the given events are emitted. If
`error` is one of the listened events, then if that fires first, the `listener`
will be given the `err` argument.
The `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the
first argument emitted from an `error` event, if applicable; `ee` is the event
emitter that fired; `event` is the string event name that fired; and `args` is an
array of the arguments that were emitted on the event.
```js
var ee1 = new EventEmitter()
var ee2 = new EventEmitter()
first([
[ee1, 'close', 'end', 'error'],
[ee2, 'error']
], function (err, ee, event, args) {
// listener invoked
})
```
#### .cancel()
The group of listeners can be cancelled before being invoked and have all the event
listeners removed from the underlying event emitters.
```js
var thunk = first([
[ee1, 'close', 'end', 'error'],
[ee2, 'error']
], function (err, ee, event, args) {
// listener invoked
})
// cancel and clean up
thunk.cancel()
```
[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square
[npm-url]: https://npmjs.org/package/ee-first
[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square
[github-url]: https://github.com/jonathanong/ee-first/tags
[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square
[travis-url]: https://travis-ci.org/jonathanong/ee-first
[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master
[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square
[license-url]: LICENSE.md
[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square
[downloads-url]: https://npmjs.org/package/ee-first
[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square
[gittip-url]: https://www.gittip.com/jonathanong/
@@ -0,0 +1,95 @@
/*!
* ee-first
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = first
/**
* Get the first event in a set of event emitters and event pairs.
*
* @param {array} stuff
* @param {function} done
* @public
*/
function first(stuff, done) {
if (!Array.isArray(stuff))
throw new TypeError('arg must be an array of [ee, events...] arrays')
var cleanups = []
for (var i = 0; i < stuff.length; i++) {
var arr = stuff[i]
if (!Array.isArray(arr) || arr.length < 2)
throw new TypeError('each array member must be [ee, events...]')
var ee = arr[0]
for (var j = 1; j < arr.length; j++) {
var event = arr[j]
var fn = listener(event, callback)
// listen to the event
ee.on(event, fn)
// push this listener to the list of cleanups
cleanups.push({
ee: ee,
event: event,
fn: fn,
})
}
}
function callback() {
cleanup()
done.apply(null, arguments)
}
function cleanup() {
var x
for (var i = 0; i < cleanups.length; i++) {
x = cleanups[i]
x.ee.removeListener(x.event, x.fn)
}
}
function thunk(fn) {
done = fn
}
thunk.cancel = cleanup
return thunk
}
/**
* Create the event listener.
* @private
*/
function listener(event, done) {
return function onevent(arg1) {
var args = new Array(arguments.length)
var ee = this
var err = event === 'error'
? arg1
: null
// copy args to prevent arguments escaping scope
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i]
}
done(err, ee, event, args)
}
}
@@ -0,0 +1,46 @@
{
"name": "ee-first",
"description": "return the first event in a set of ee/event pairs",
"version": "1.1.1",
"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": "git://github.com/jonathanong/ee-first"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "2.2.5"
},
"files": [
"index.js",
"LICENSE"
],
"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/"
},
"readme": "# EE First\n\n[![NPM version][npm-image]][npm-url]\n[![Build status][travis-image]][travis-url]\n[![Test coverage][coveralls-image]][coveralls-url]\n[![License][license-image]][license-url]\n[![Downloads][downloads-image]][downloads-url]\n[![Gittip][gittip-image]][gittip-url]\n\nGet the first event in a set of event emitters and event pairs,\nthen clean up after itself.\n\n## Install\n\n```sh\n$ npm install ee-first\n```\n\n## API\n\n```js\nvar first = require('ee-first')\n```\n\n### first(arr, listener)\n\nInvoke `listener` on the first event from the list specified in `arr`. `arr` is\nan array of arrays, with each array in the format `[ee, ...event]`. `listener`\nwill be called only once, the first time any of the given events are emitted. If\n`error` is one of the listened events, then if that fires first, the `listener`\nwill be given the `err` argument.\n\nThe `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the\nfirst argument emitted from an `error` event, if applicable; `ee` is the event\nemitter that fired; `event` is the string event name that fired; and `args` is an\narray of the arguments that were emitted on the event.\n\n```js\nvar ee1 = new EventEmitter()\nvar ee2 = new EventEmitter()\n\nfirst([\n [ee1, 'close', 'end', 'error'],\n [ee2, 'error']\n], function (err, ee, event, args) {\n // listener invoked\n})\n```\n\n#### .cancel()\n\nThe group of listeners can be cancelled before being invoked and have all the event\nlisteners removed from the underlying event emitters.\n\n```js\nvar thunk = first([\n [ee1, 'close', 'end', 'error'],\n [ee2, 'error']\n], function (err, ee, event, args) {\n // listener invoked\n})\n\n// cancel and clean up\nthunk.cancel()\n```\n\n[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/ee-first\n[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square\n[github-url]: https://github.com/jonathanong/ee-first/tags\n[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square\n[travis-url]: https://travis-ci.org/jonathanong/ee-first\n[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square\n[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master\n[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square\n[license-url]: LICENSE.md\n[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square\n[downloads-url]: https://npmjs.org/package/ee-first\n[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square\n[gittip-url]: https://www.gittip.com/jonathanong/\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/jonathanong/ee-first/issues"
},
"homepage": "https://github.com/jonathanong/ee-first",
"_id": "ee-first@1.1.1",
"dist": {
"shasum": "e29762f41f0505c5212724f3857703d1d8f5d4de"
},
"_from": "ee-first@1.1.1",
"_resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
}
File diff suppressed because one or more lines are too long
+4
View File
@@ -0,0 +1,4 @@
benchmark/
coverage/
test/
.travis.yml
+42
View File
@@ -0,0 +1,42 @@
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`

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