added more filtering

This commit is contained in:
martind2000@gmail.com 2015-08-14 20:58:05 +01:00
parent 9ae52acdec
commit 0e22bc7ec4
169 changed files with 5546 additions and 30956 deletions

BIN
html/assets/tf_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

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

6
node_modules/express/LICENSE generated vendored
View File

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

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

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

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

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

View File

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

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

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

View File

@ -1,36 +0,0 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Initialization middleware, exposing the
* request and response to each other, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || Object.create(null);
next();
};
};

View File

@ -1,51 +0,0 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
*/
var parseUrl = require('parseurl');
var qs = require('qs');
/**
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function query(options) {
var opts = Object.create(options || null);
var queryparse = qs.parse;
if (typeof options === 'function') {
queryparse = options;
opts = undefined;
}
if (opts !== undefined) {
if (opts.allowDots === undefined) {
opts.allowDots = false;
}
if (opts.allowPrototypes === undefined) {
opts.allowPrototypes = true;
}
}
return function query(req, res, next){
if (!req.query) {
var val = parseUrl(req).query;
req.query = queryparse(val, opts);
}
next();
};
};

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

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

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,176 +0,0 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var pathRegexp = require('path-to-regexp');
var debug = require('debug')('express:router:layer');
/**
* Module variables.
* @private
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Module exports.
* @public
*/
module.exports = Layer;
function Layer(path, options, fn) {
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
}
debug('new %s', path);
var opts = options || {};
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], opts);
if (path === '/' && opts.end === false) {
this.regexp.fast_slash = true;
}
}
/**
* Handle the error for the layer.
*
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;
if (fn.length !== 4) {
// not a standard error handler
return next(error);
}
try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};
/**
* Handle the request for the layer.
*
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
if (fn.length > 3) {
// not a standard request handler
return next();
}
try {
fn(req, res, next);
} catch (err) {
next(err);
}
};
/**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
*/
Layer.prototype.match = function match(path) {
if (path == null) {
// no path, nothing matches
this.params = undefined;
this.path = undefined;
return false;
}
if (this.regexp.fast_slash) {
// fast path non-ending match for / (everything matches)
this.params = {};
this.path = '';
return true;
}
var m = this.regexp.exec(path);
if (!m) {
this.params = undefined;
this.path = undefined;
return false;
}
// store values
this.params = {};
this.path = m[0];
var keys = this.keys;
var params = this.params;
for (var i = 1; i < m.length; i++) {
var key = keys[i - 1];
var prop = key.name;
var val = decode_param(m[i]);
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
params[prop] = val;
}
}
return true;
};
/**
* Decode param value.
*
* @param {string} val
* @return {string}
* @private
*/
function decode_param(val) {
if (typeof val !== 'string' || val.length === 0) {
return val;
}
try {
return decodeURIComponent(val);
} catch (err) {
if (err instanceof URIError) {
err.message = 'Failed to decode param \'' + val + '\'';
err.status = err.statusCode = 400;
}
throw err;
}
}

View File

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

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

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

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

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

View File

@ -1,158 +0,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

View File

@ -1,23 +0,0 @@
(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.

View File

@ -1,135 +0,0 @@
# 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

View File

@ -1,231 +0,0 @@
/*!
* 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';
}

View File

@ -1,147 +0,0 @@
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

View File

@ -1,23 +0,0 @@
(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.

View File

@ -1,103 +0,0 @@
# 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

View File

@ -1,188 +0,0 @@
/*!
* 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
return
}
}
// set the extension -> mime
types[extension] = type
}
})
}

View File

@ -1,241 +0,0 @@
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

View File

@ -1,22 +0,0 @@
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.

View File

@ -1,82 +0,0 @@
# 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/

View File

@ -1,11 +0,0 @@
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = require('./db.json')

View File

@ -1,76 +0,0 @@
{
"name": "mime-db",
"description": "Media Type Database",
"version": "1.15.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.9.33",
"co": "4.6.0",
"cogent": "1.0.1",
"csv-parse": "0.1.3",
"gnode": "0.1.1",
"istanbul": "0.3.17",
"mocha": "1.21.5",
"raw-body": "2.1.2",
"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.15.0",
"dist": {
"shasum": "a117ffe20c1f953f119ddd626a125e1a96c4570c"
},
"_from": "mime-db@1.15.0",
"_resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.15.0.tgz"
}

View File

@ -1,84 +0,0 @@
{
"name": "mime-types",
"description": "The ultimate javascript content-type utility.",
"version": "2.1.3",
"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+https://github.com/jshttp/mime-types.git"
},
"dependencies": {
"mime-db": "~1.15.0"
},
"devDependencies": {
"istanbul": "0.3.17",
"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"
},
"gitHead": "565c49ad5683d4a123a170da3444ed32ce426c3a",
"bugs": {
"url": "https://github.com/jshttp/mime-types/issues"
},
"homepage": "https://github.com/jshttp/mime-types",
"_id": "mime-types@2.1.3",
"_shasum": "f259849c7eb1f85b8f5f826187278a7f74f0c966",
"_from": "mime-types@>=2.1.3 <2.2.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "f259849c7eb1f85b8f5f826187278a7f74f0c966",
"tarball": "http://registry.npmjs.org/mime-types/-/mime-types-2.1.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.3.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,76 +0,0 @@
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

View File

@ -1,24 +0,0 @@
(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.

View File

@ -1,203 +0,0 @@
# 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

View File

@ -1,62 +0,0 @@
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;

View File

@ -1,102 +0,0 @@
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;
}

View File

@ -1,118 +0,0 @@
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;
}

View File

@ -1,112 +0,0 @@
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;
}

View File

@ -1,179 +0,0 @@
/**
* 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;
}

View File

@ -1,86 +0,0 @@
{
"name": "negotiator",
"description": "HTTP content negotiation",
"version": "0.5.3",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Federico Romero",
"email": "federico.romero@outboxlabs.com"
},
{
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"url": "http://blog.izs.me/"
}
],
"license": "MIT",
"keywords": [
"http",
"content negotiation",
"accept",
"accept-language",
"accept-encoding",
"accept-charset"
],
"repository": {
"type": "git",
"url": "git+https://github.com/jshttp/negotiator.git"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "~1.21.5"
},
"files": [
"lib/",
"HISTORY.md",
"LICENSE",
"index.js",
"README.md"
],
"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/"
},
"gitHead": "cbb717b3f164f25820f90b160cda6d0166b9d922",
"bugs": {
"url": "https://github.com/jshttp/negotiator/issues"
},
"homepage": "https://github.com/jshttp/negotiator",
"_id": "negotiator@0.5.3",
"_shasum": "269d5c476810ec92edbe7b6c2f28316384f9a7e8",
"_from": "negotiator@0.5.3",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "federomero",
"email": "federomero@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
}
],
"dist": {
"shasum": "269d5c476810ec92edbe7b6c2f28316384f9a7e8",
"tarball": "http://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,98 +0,0 @@
{
"name": "accepts",
"description": "Higher-level content negotiation",
"version": "1.2.11",
"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+https://github.com/jshttp/accepts.git"
},
"dependencies": {
"mime-types": "~2.1.3",
"negotiator": "0.5.3"
},
"devDependencies": {
"istanbul": "0.3.17",
"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"
],
"gitHead": "c9c8adea7bb8395089ead858fc059a38e99ac3bc",
"bugs": {
"url": "https://github.com/jshttp/accepts/issues"
},
"homepage": "https://github.com/jshttp/accepts",
"_id": "accepts@1.2.11",
"_shasum": "d341c6e3b420489632f0f4f8d2ad4fd9ddf374e0",
"_from": "accepts@>=1.2.10 <1.3.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "federomero",
"email": "federomero@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
},
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "mscdex",
"email": "mscdex@mscdex.net"
},
{
"name": "defunctzombie",
"email": "shtylman@gmail.com"
}
],
"dist": {
"shasum": "d341c6e3b420489632f0f4f8d2ad4fd9ddf374e0",
"tarball": "http://registry.npmjs.org/accepts/-/accepts-1.2.11.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.11.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,21 +0,0 @@
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.

View File

@ -1,43 +0,0 @@
# 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

View File

@ -1,57 +0,0 @@
/**
* Recursive flatten function with depth.
*
* @param {Array} array
* @param {Array} result
* @param {Number} depth
* @return {Array}
*/
function flattenDepth (array, result, depth) {
for (var i = 0; i < array.length; i++) {
var value = array[i]
if (depth > 0 && Array.isArray(value)) {
flattenDepth(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}
*/
module.exports = function (array, depth) {
if (depth == null) {
return flattenForever(array, [])
}
return flattenDepth(array, [], depth)
}

View File

@ -1,47 +0,0 @@
{
"name": "array-flatten",
"version": "1.1.0",
"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.0",
"dist": {
"shasum": "398a1408cf23e6b1b3d5b1235cdf0f300948c5bc"
},
"_from": "array-flatten@1.1.0",
"_resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.0.tgz"
}

View File

@ -14,7 +14,7 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/visionmedia/node-cookie-signature.git"
"url": "https://github.com/visionmedia/node-cookie-signature.git"
},
"dependencies": {},
"devDependencies": {
@ -54,6 +54,5 @@
"tarball": "http://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
}

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@
],
"repository": {
"type": "git",
"url": "git+https://github.com/jshttp/cookie.git"
"url": "https://github.com/jshttp/cookie"
},
"devDependencies": {
"istanbul": "0.3.9",
@ -64,6 +64,5 @@
"tarball": "http://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
}

View File

@ -10,7 +10,7 @@
],
"repository": {
"type": "git",
"url": "git+https://github.com/component/escape-html.git"
"url": "https://github.com/component/escape-html"
},
"files": [
"LICENSE",
@ -46,6 +46,5 @@
"tarball": "http://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz"
}

View File

@ -1,90 +0,0 @@
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

View File

@ -1,22 +0,0 @@
(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.

View File

@ -1,133 +0,0 @@
# 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

View File

@ -1,151 +0,0 @@
/*!
* 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()
}

View File

@ -1,4 +0,0 @@
1.0.0 / 2015-06-14
==================
* Initial release

View File

@ -1,22 +0,0 @@
(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.

View File

@ -1,43 +0,0 @@
# 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

View File

@ -1,69 +0,0 @@
/*!
* 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)
}
}

View File

@ -1,59 +0,0 @@
{
"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+https://github.com/stream-utils/unpipe.git"
},
"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/"
},
"gitHead": "d2df901c06487430e78dca62b6edb8bb2fc5e99d",
"bugs": {
"url": "https://github.com/stream-utils/unpipe/issues"
},
"homepage": "https://github.com/stream-utils/unpipe",
"_id": "unpipe@1.0.0",
"_shasum": "b2bf4ee8514aae6165b4817829d21b2ef49904ec",
"_from": "unpipe@>=1.0.0 <1.1.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "b2bf4ee8514aae6165b4817829d21b2ef49904ec",
"tarball": "http://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,81 +0,0 @@
{
"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+https://github.com/pillarjs/finalhandler.git"
},
"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/"
},
"gitHead": "fe4e4de9ebb0f3831493ad75119ee6ba40542853",
"bugs": {
"url": "https://github.com/pillarjs/finalhandler/issues"
},
"homepage": "https://github.com/pillarjs/finalhandler",
"_id": "finalhandler@0.4.0",
"_shasum": "965a52d9e8d05d2b857548541fb89b53a2497d9b",
"_from": "finalhandler@0.4.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
},
{
"name": "defunctzombie",
"email": "shtylman@gmail.com"
}
],
"dist": {
"shasum": "965a52d9e8d05d2b857548541fb89b53a2497d9b",
"tarball": "http://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,88 +0,0 @@
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

View File

@ -1,23 +0,0 @@
(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.

View File

@ -1,154 +0,0 @@
# 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

View File

@ -1,196 +0,0 @@
/*!
* 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)
}
}

View File

@ -1,22 +0,0 @@
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.

View File

@ -1,80 +0,0 @@
# 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/

View File

@ -1,95 +0,0 @@
/*!
* 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)
}
}

View File

@ -1,64 +0,0 @@
{
"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+https://github.com/jonathanong/ee-first.git"
},
"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/"
},
"gitHead": "512e0ce4cc3643f603708f965a97b61b1a9c0441",
"bugs": {
"url": "https://github.com/jonathanong/ee-first/issues"
},
"homepage": "https://github.com/jonathanong/ee-first",
"_id": "ee-first@1.1.1",
"_shasum": "590c61156b0ae2f4f0255732a158b266bc56b21d",
"_from": "ee-first@1.1.1",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "590c61156b0ae2f4f0255732a158b266bc56b21d",
"tarball": "http://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,71 +0,0 @@
{
"name": "on-finished",
"description": "Execute a callback when a request closes, finishes, or errors",
"version": "2.3.0",
"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+https://github.com/jshttp/on-finished.git"
},
"dependencies": {
"ee-first": "1.1.1"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "2.2.5"
},
"engines": {
"node": ">= 0.8"
},
"files": [
"HISTORY.md",
"LICENSE",
"index.js"
],
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "34babcb58126a416fcf5205768204f2e12699dda",
"bugs": {
"url": "https://github.com/jshttp/on-finished/issues"
},
"homepage": "https://github.com/jshttp/on-finished",
"_id": "on-finished@2.3.0",
"_shasum": "20f1336481b083cd75337992a16971aa2d906947",
"_from": "on-finished@>=2.3.0 <2.4.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
}
],
"dist": {
"shasum": "20f1336481b083cd75337992a16971aa2d906947",
"tarball": "http://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,21 +0,0 @@
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.

View File

@ -1,35 +0,0 @@
# Path-to-RegExp
Turn an Express-style path string such as `/user/:name` into a regular expression.
**Note:** This is a legacy branch. You should upgrade to `1.x`. If you find you are stuck on this version, your code will need to take into account the `index` property on the keys.
## Usage
```javascript
var pathToRegexp = require('path-to-regexp');
```
### pathToRegexp(path, keys, options)
- **path** A string in the express format, an array of such strings, or a regular expression
- **keys** An array to be populated with the keys present in the url. Once the function completes, this will be an array of strings.
- **options**
- **options.sensitive** Defaults to false, set this to true to make routes case sensitive
- **options.strict** Defaults to false, set this to true to make the trailing slash matter.
- **options.end** Defaults to true, set this to false to only match the prefix of the URL.
```javascript
var keys = [];
var exp = pathToRegexp('/foo/:bar', keys);
//keys = ['bar']
//exp = /^\/foo\/(?:([^\/]+?))\/?$/i
```
## Live Demo
You can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.com/express-route-tester/).
## License
MIT

View File

@ -1,117 +0,0 @@
/**
* Expose `pathtoRegexp`.
*/
module.exports = pathtoRegexp;
/**
* Match matching groups in a regular expression.
*/
var MATCHING_GROUP_REGEXP = /\((?!\?)/g;
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Object} options
* @return {RegExp}
* @api private
*/
function pathtoRegexp(path, keys, options) {
options = options || {};
keys = keys || [];
var strict = options.strict;
var end = options.end !== false;
var flags = options.sensitive ? '' : 'i';
var extraOffset = 0;
var keysOffset = keys.length;
var i = 0;
var name = 0;
var m;
if (path instanceof RegExp) {
while (m = MATCHING_GROUP_REGEXP.exec(path.source)) {
keys.push({
name: name++,
optional: false,
offset: m.index
});
}
return path;
}
if (Array.isArray(path)) {
// Map array parts into regexps and return their source. We also pass
// the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together.
path = path.map(function (value) {
return pathtoRegexp(value, keys, options).source;
});
return new RegExp('(?:' + path.join('|') + ')', flags);
}
path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?'))
.replace(/\/\(/g, '/(?:')
.replace(/([\/\.])/g, '\\$1')
.replace(/(\\\/)?(\\\.)?:(\w+)(\(.*?\))?(\*)?(\?)?/g, function (match, slash, format, key, capture, star, optional, offset) {
slash = slash || '';
format = format || '';
capture = capture || '([^\\/' + format + ']+?)';
optional = optional || '';
keys.push({
name: key,
optional: !!optional,
offset: offset + extraOffset
});
var result = ''
+ (optional ? '' : slash)
+ '(?:'
+ format + (optional ? slash : '') + capture
+ (star ? '((?:[\\/' + format + '].+?)?)' : '')
+ ')'
+ optional;
extraOffset += result.length - match.length;
return result;
})
.replace(/\*/g, function (star, index) {
var len = keys.length
while (len-- > keysOffset && keys[len].offset > index) {
keys[len].offset += 3;
}
return '(.*)';
});
// This is a workaround for handling unnamed matching groups.
while (m = MATCHING_GROUP_REGEXP.exec(path)) {
if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m.index) {
keys.splice(keysOffset + i, 0, {
name: name++, // Unnamed matching groups must be consistently linear.
optional: false,
offset: m.index
});
}
i++;
}
// If the path is non-ending, match until the end or a slash.
path += (end ? '$' : (path[path.length - 1] === '/' ? '' : '(?=\\/|$)'));
return new RegExp(path, flags);
};

View File

@ -1,42 +0,0 @@
{
"name": "path-to-regexp",
"description": "Express style path to RegExp utility",
"version": "0.1.6",
"files": [
"index.js",
"LICENSE"
],
"scripts": {
"test": "istanbul cover _mocha -- -R spec"
},
"keywords": [
"express",
"regexp"
],
"component": {
"scripts": {
"path-to-regexp": "index.js"
}
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/component/path-to-regexp.git"
},
"devDependencies": {
"mocha": "^1.17.1",
"istanbul": "^0.2.6"
},
"readme": "# Path-to-RegExp\n\nTurn an Express-style path string such as `/user/:name` into a regular expression.\n\n**Note:** This is a legacy branch. You should upgrade to `1.x`. If you find you are stuck on this version, your code will need to take into account the `index` property on the keys.\n\n## Usage\n\n```javascript\nvar pathToRegexp = require('path-to-regexp');\n```\n\n### pathToRegexp(path, keys, options)\n\n - **path** A string in the express format, an array of such strings, or a regular expression\n - **keys** An array to be populated with the keys present in the url. Once the function completes, this will be an array of strings.\n - **options**\n - **options.sensitive** Defaults to false, set this to true to make routes case sensitive\n - **options.strict** Defaults to false, set this to true to make the trailing slash matter.\n - **options.end** Defaults to true, set this to false to only match the prefix of the URL.\n\n```javascript\nvar keys = [];\nvar exp = pathToRegexp('/foo/:bar', keys);\n//keys = ['bar']\n//exp = /^\\/foo\\/(?:([^\\/]+?))\\/?$/i\n```\n\n## Live Demo\n\nYou can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.com/express-route-tester/).\n\n## License\n\n MIT\n",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/component/path-to-regexp/issues"
},
"homepage": "https://github.com/component/path-to-regexp",
"_id": "path-to-regexp@0.1.6",
"dist": {
"shasum": "03340d11b9f9f3dcd2c506635652eb1cee8d05e4"
},
"_from": "path-to-regexp@0.1.6",
"_resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.6.tgz"
}

View File

@ -1 +0,0 @@
dist

View File

@ -1,19 +0,0 @@
.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
config.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
coverage.*
lib-cov
complexity.md
dist

View File

@ -1,6 +0,0 @@
language: node_js
node_js:
- 0.10
- 0.12
- iojs

View File

@ -1,88 +0,0 @@
## [**3.1.0**](https://github.com/hapijs/qs/issues?milestone=24&state=open)
- [**#89**](https://github.com/hapijs/qs/issues/89) Add option to disable "Transform dot notation to bracket notation"
## [**3.0.0**](https://github.com/hapijs/qs/issues?milestone=23&state=closed)
- [**#77**](https://github.com/hapijs/qs/issues/77) Perf boost
- [**#60**](https://github.com/hapijs/qs/issues/60) Add explicit option to disable array parsing
- [**#80**](https://github.com/hapijs/qs/issues/80) qs.parse silently drops properties
- [**#74**](https://github.com/hapijs/qs/issues/74) Bad parse when turning array into object
- [**#81**](https://github.com/hapijs/qs/issues/81) Add a `filter` option
- [**#68**](https://github.com/hapijs/qs/issues/68) Fixed issue with recursion and passing strings into objects.
- [**#66**](https://github.com/hapijs/qs/issues/66) Add mixed array and object dot notation support Closes: #47
- [**#76**](https://github.com/hapijs/qs/issues/76) RFC 3986
- [**#85**](https://github.com/hapijs/qs/issues/85) No equal sign
- [**#84**](https://github.com/hapijs/qs/issues/84) update license attribute
## [**2.4.1**](https://github.com/hapijs/qs/issues?milestone=20&state=closed)
- [**#73**](https://github.com/hapijs/qs/issues/73) Property 'hasOwnProperty' of object #<Object> is not a function
## [**2.4.0**](https://github.com/hapijs/qs/issues?milestone=19&state=closed)
- [**#70**](https://github.com/hapijs/qs/issues/70) Add arrayFormat option
## [**2.3.3**](https://github.com/hapijs/qs/issues?milestone=18&state=closed)
- [**#59**](https://github.com/hapijs/qs/issues/59) make sure array indexes are >= 0, closes #57
- [**#58**](https://github.com/hapijs/qs/issues/58) make qs usable for browser loader
## [**2.3.2**](https://github.com/hapijs/qs/issues?milestone=17&state=closed)
- [**#55**](https://github.com/hapijs/qs/issues/55) allow merging a string into an object
## [**2.3.1**](https://github.com/hapijs/qs/issues?milestone=16&state=closed)
- [**#52**](https://github.com/hapijs/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
## [**2.3.0**](https://github.com/hapijs/qs/issues?milestone=15&state=closed)
- [**#50**](https://github.com/hapijs/qs/issues/50) add option to omit array indices, closes #46
## [**2.2.5**](https://github.com/hapijs/qs/issues?milestone=14&state=closed)
- [**#39**](https://github.com/hapijs/qs/issues/39) Is there an alternative to Buffer.isBuffer?
- [**#49**](https://github.com/hapijs/qs/issues/49) refactor utils.merge, fixes #45
- [**#41**](https://github.com/hapijs/qs/issues/41) avoid browserifying Buffer, for #39
## [**2.2.4**](https://github.com/hapijs/qs/issues?milestone=13&state=closed)
- [**#38**](https://github.com/hapijs/qs/issues/38) how to handle object keys beginning with a number
## [**2.2.3**](https://github.com/hapijs/qs/issues?milestone=12&state=closed)
- [**#37**](https://github.com/hapijs/qs/issues/37) parser discards first empty value in array
- [**#36**](https://github.com/hapijs/qs/issues/36) Update to lab 4.x
## [**2.2.2**](https://github.com/hapijs/qs/issues?milestone=11&state=closed)
- [**#33**](https://github.com/hapijs/qs/issues/33) Error when plain object in a value
- [**#34**](https://github.com/hapijs/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
- [**#24**](https://github.com/hapijs/qs/issues/24) Changelog? Semver?
## [**2.2.1**](https://github.com/hapijs/qs/issues?milestone=10&state=closed)
- [**#32**](https://github.com/hapijs/qs/issues/32) account for circular references properly, closes #31
- [**#31**](https://github.com/hapijs/qs/issues/31) qs.parse stackoverflow on circular objects
## [**2.2.0**](https://github.com/hapijs/qs/issues?milestone=9&state=closed)
- [**#26**](https://github.com/hapijs/qs/issues/26) Don't use Buffer global if it's not present
- [**#30**](https://github.com/hapijs/qs/issues/30) Bug when merging non-object values into arrays
- [**#29**](https://github.com/hapijs/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
- [**#23**](https://github.com/hapijs/qs/issues/23) Ability to not limit parameters?
## [**2.1.0**](https://github.com/hapijs/qs/issues?milestone=8&state=closed)
- [**#22**](https://github.com/hapijs/qs/issues/22) Enable using a RegExp as delimiter
## [**2.0.0**](https://github.com/hapijs/qs/issues?milestone=7&state=closed)
- [**#18**](https://github.com/hapijs/qs/issues/18) Why is there arrayLimit?
- [**#20**](https://github.com/hapijs/qs/issues/20) Configurable parametersLimit
- [**#21**](https://github.com/hapijs/qs/issues/21) make all limits optional, for #18, for #20
## [**1.2.2**](https://github.com/hapijs/qs/issues?milestone=6&state=closed)
- [**#19**](https://github.com/hapijs/qs/issues/19) Don't overwrite null values
## [**1.2.1**](https://github.com/hapijs/qs/issues?milestone=5&state=closed)
- [**#16**](https://github.com/hapijs/qs/issues/16) ignore non-string delimiters
- [**#15**](https://github.com/hapijs/qs/issues/15) Close code block
## [**1.2.0**](https://github.com/hapijs/qs/issues?milestone=4&state=closed)
- [**#12**](https://github.com/hapijs/qs/issues/12) Add optional delim argument
- [**#13**](https://github.com/hapijs/qs/issues/13) fix #11: flattened keys in array are now correctly parsed
## [**1.1.0**](https://github.com/hapijs/qs/issues?milestone=3&state=closed)
- [**#7**](https://github.com/hapijs/qs/issues/7) Empty values of a POST array disappear after being submitted
- [**#9**](https://github.com/hapijs/qs/issues/9) Should not omit equals signs (=) when value is null
- [**#6**](https://github.com/hapijs/qs/issues/6) Minor grammar fix in README
## [**1.0.2**](https://github.com/hapijs/qs/issues?milestone=2&state=closed)
- [**#5**](https://github.com/hapijs/qs/issues/5) array holes incorrectly copied into object on large index

View File

@ -1 +0,0 @@
Please view our [hapijs contributing guide](https://github.com/hapijs/hapi/blob/master/CONTRIBUTING.md).

View File

@ -1,28 +0,0 @@
Copyright (c) 2014 Nathan LaFreniere and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *
The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors

View File

@ -1,317 +0,0 @@
# qs
A querystring parsing and stringifying library with some added security.
[![Build Status](https://secure.travis-ci.org/hapijs/qs.svg)](http://travis-ci.org/hapijs/qs)
Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf)
The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
## Usage
```javascript
var Qs = require('qs');
var obj = Qs.parse('a=c'); // { a: 'c' }
var str = Qs.stringify(obj); // 'a=c'
```
### Parsing Objects
```javascript
Qs.parse(string, [options]);
```
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`, or prefixing the sub-key with a dot `.`.
For example, the string `'foo[bar]=baz'` converts to:
```javascript
{
foo: {
bar: 'baz'
}
}
```
When using the `plainObjects` option the parsed value is returned as a plain object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
```javascript
Qs.parse('a.hasOwnProperty=b', { plainObjects: true });
// { a: { hasOwnProperty: 'b' } }
```
By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
```javascript
Qs.parse('a.hasOwnProperty=b', { allowPrototypes: true });
// { a: { hasOwnProperty: 'b' } }
```
URI encoded strings work too:
```javascript
Qs.parse('a%5Bb%5D=c');
// { a: { b: 'c' } }
```
You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
```javascript
{
foo: {
bar: {
baz: 'foobarbaz'
}
}
}
```
By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
```javascript
{
a: {
b: {
c: {
d: {
e: {
f: {
'[g][h][i]': 'j'
}
}
}
}
}
}
}
```
This depth can be overridden by passing a `depth` option to `Qs.parse(string, [options])`:
```javascript
Qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
// { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }
```
The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
```javascript
Qs.parse('a=b&c=d', { parameterLimit: 1 });
// { a: 'b' }
```
An optional delimiter can also be passed:
```javascript
Qs.parse('a=b;c=d', { delimiter: ';' });
// { a: 'b', c: 'd' }
```
Delimiters can be a regular expression too:
```javascript
Qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
// { a: 'b', c: 'd', e: 'f' }
```
Option `allowDots` can be used to disable dot notation:
```javascript
Qs.parse('a.b=c', { allowDots: false });
// { 'a.b': 'c' } }
```
### Parsing Arrays
**qs** can also parse arrays using a similar `[]` notation:
```javascript
Qs.parse('a[]=b&a[]=c');
// { a: ['b', 'c'] }
```
You may specify an index as well:
```javascript
Qs.parse('a[1]=c&a[0]=b');
// { a: ['b', 'c'] }
```
Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
their order:
```javascript
Qs.parse('a[1]=b&a[15]=c');
// { a: ['b', 'c'] }
```
Note that an empty string is also a value, and will be preserved:
```javascript
Qs.parse('a[]=&a[]=b');
// { a: ['', 'b'] }
Qs.parse('a[0]=b&a[1]=&a[2]=c');
// { a: ['b', '', 'c'] }
```
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
instead be converted to an object with the index as the key:
```javascript
Qs.parse('a[100]=b');
// { a: { '100': 'b' } }
```
This limit can be overridden by passing an `arrayLimit` option:
```javascript
Qs.parse('a[1]=b', { arrayLimit: 0 });
// { a: { '1': 'b' } }
```
To disable array parsing entirely, set `parseArrays` to `false`.
```javascript
Qs.parse('a[]=b', { parseArrays: false });
// { a: { '0': 'b' } }
```
If you mix notations, **qs** will merge the two items into an object:
```javascript
Qs.parse('a[0]=b&a[b]=c');
// { a: { '0': 'b', b: 'c' } }
```
You can also create arrays of objects:
```javascript
Qs.parse('a[][b]=c');
// { a: [{ b: 'c' }] }
```
### Stringifying
```javascript
Qs.stringify(object, [options]);
```
When stringifying, **qs** always URI encodes output. Objects are stringified as you would expect:
```javascript
Qs.stringify({ a: 'b' });
// 'a=b'
Qs.stringify({ a: { b: 'c' } });
// 'a%5Bb%5D=c'
```
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
When arrays are stringified, by default they are given explicit indices:
```javascript
Qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d'
```
You may override this by setting the `indices` option to `false`:
```javascript
Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
// 'a=b&a=c&a=d'
```
You may use the `arrayFormat` option to specify the format of the output array
```javascript
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
```
Empty strings and null values will omit the value, but the equals sign (=) remains in place:
```javascript
Qs.stringify({ a: '' });
// 'a='
```
Properties that are set to `undefined` will be omitted entirely:
```javascript
Qs.stringify({ a: null, b: undefined });
// 'a='
```
The delimiter may be overridden with stringify as well:
```javascript
Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' });
// 'a=b;c=d'
```
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
pass an array, it will be used to select properties and array indices for stringification:
```javascript
function filterFunc(prefix, value) {
if (prefix == 'b') {
// Return an `undefined` value to omit a property.
return;
}
if (prefix == 'e[f]') {
return value.getTime();
}
if (prefix == 'e[g][0]') {
return value * 2;
}
return value;
}
Qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc })
// 'a=b&c=d&e[f]=123&e[g][0]=4'
Qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] })
// 'a=b&e=f'
Qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] })
// 'a[0]=b&a[2]=d'
```
### Handling of `null` values
By default, `null` values are treated like empty strings:
```javascript
Qs.stringify({ a: null, b: '' });
// 'a=&b='
```
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
```javascript
Qs.parse('a&b=')
// { a: '', b: '' }
```
To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
values have no `=` sign:
```javascript
Qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
// 'a&b='
```
To parse values without `=` back to `null` use the `strictNullHandling` flag:
```javascript
Qs.parse('a&b=', { strictNullHandling: true });
// { a: null, b: '' }
```

View File

@ -1,22 +0,0 @@
{
"name": "qs",
"main": "dist/qs.js",
"version": "3.0.0",
"homepage": "https://github.com/hapijs/qs",
"authors": [
"Nathan LaFreniere <quitlahok@gmail.com>"
],
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"keywords": [
"querystring",
"qs"
],
"license": "BSD-3-Clause",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View File

@ -1,15 +0,0 @@
// Load modules
var Stringify = require('./stringify');
var Parse = require('./parse');
// Declare internals
var internals = {};
module.exports = {
stringify: Stringify,
parse: Parse
};

View File

@ -1,186 +0,0 @@
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
depth: 5,
arrayLimit: 20,
parameterLimit: 1000,
strictNullHandling: false,
plainObjects: false,
allowPrototypes: false
};
internals.parseValues = function (str, options) {
var obj = {};
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
for (var i = 0, il = parts.length; i < il; ++i) {
var part = parts[i];
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
if (pos === -1) {
obj[Utils.decode(part)] = '';
if (options.strictNullHandling) {
obj[Utils.decode(part)] = null;
}
}
else {
var key = Utils.decode(part.slice(0, pos));
var val = Utils.decode(part.slice(pos + 1));
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
obj[key] = val;
}
else {
obj[key] = [].concat(obj[key]).concat(val);
}
}
}
return obj;
};
internals.parseObject = function (chain, val, options) {
if (!chain.length) {
return val;
}
var root = chain.shift();
var obj;
if (root === '[]') {
obj = [];
obj = obj.concat(internals.parseObject(chain, val, options));
}
else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
var index = parseInt(cleanRoot, 10);
var indexString = '' + index;
if (!isNaN(index) &&
root !== cleanRoot &&
indexString === cleanRoot &&
index >= 0 &&
(options.parseArrays &&
index <= options.arrayLimit)) {
obj = [];
obj[index] = internals.parseObject(chain, val, options);
}
else {
obj[cleanRoot] = internals.parseObject(chain, val, options);
}
}
return obj;
};
internals.parseKeys = function (key, val, options) {
if (!key) {
return;
}
// Transform dot notation to bracket notation
if (options.allowDots) {
key = key.replace(/\.([^\.\[]+)/g, '[$1]');
}
// The regex chunks
var parent = /^([^\[\]]*)/;
var child = /(\[[^\[\]]*\])/g;
// Get the parent
var segment = parent.exec(key);
// Stash the parent if it exists
var keys = [];
if (segment[1]) {
// If we aren't using plain objects, optionally prefix keys
// that would overwrite object prototype properties
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1])) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(segment[1]);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while ((segment = child.exec(key)) !== null && i < options.depth) {
++i;
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
if (!options.allowPrototypes) {
continue;
}
}
keys.push(segment[1]);
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return internals.parseObject(keys, val, options);
};
module.exports = function (str, options) {
options = options || {};
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
options.parseArrays = options.parseArrays !== false;
options.allowDots = options.allowDots !== false;
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : internals.plainObjects;
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : internals.allowPrototypes;
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
if (str === '' ||
str === null ||
typeof str === 'undefined') {
return options.plainObjects ? Object.create(null) : {};
}
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
var obj = options.plainObjects ? Object.create(null) : {};
// Iterate over the keys and setup the new object
var keys = Object.keys(tempObj);
for (var i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
var newObj = internals.parseKeys(key, tempObj[key], options);
obj = Utils.merge(obj, newObj, options);
}
return Utils.compact(obj);
};

View File

@ -1,121 +0,0 @@
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
arrayPrefixGenerators: {
brackets: function (prefix, key) {
return prefix + '[]';
},
indices: function (prefix, key) {
return prefix + '[' + key + ']';
},
repeat: function (prefix, key) {
return prefix;
}
},
strictNullHandling: false
};
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, filter) {
if (typeof filter === 'function') {
obj = filter(prefix, obj);
}
else if (Utils.isBuffer(obj)) {
obj = obj.toString();
}
else if (obj instanceof Date) {
obj = obj.toISOString();
}
else if (obj === null) {
if (strictNullHandling) {
return Utils.encode(prefix);
}
obj = '';
}
if (typeof obj === 'string' ||
typeof obj === 'number' ||
typeof obj === 'boolean') {
return [Utils.encode(prefix) + '=' + Utils.encode(obj)];
}
var values = [];
if (typeof obj === 'undefined') {
return values;
}
var objKeys = Array.isArray(filter) ? filter : Object.keys(obj);
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
if (Array.isArray(obj)) {
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, filter));
}
else {
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, filter));
}
}
return values;
};
module.exports = function (obj, options) {
options = options || {};
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
var objKeys;
var filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
}
else if (Array.isArray(options.filter)) {
objKeys = filter = options.filter;
}
var keys = [];
if (typeof obj !== 'object' ||
obj === null) {
return '';
}
var arrayFormat;
if (options.arrayFormat in internals.arrayPrefixGenerators) {
arrayFormat = options.arrayFormat;
}
else if ('indices' in options) {
arrayFormat = options.indices ? 'indices' : 'repeat';
}
else {
arrayFormat = 'indices';
}
var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat];
if (!objKeys) {
objKeys = Object.keys(obj);
}
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, filter));
}
return keys.join(delimiter);
};

View File

@ -1,190 +0,0 @@
// Load modules
// Declare internals
var internals = {};
internals.hexTable = new Array(256);
for (var h = 0; h < 256; ++h) {
internals.hexTable[h] = '%' + ((h < 16 ? '0' : '') + h.toString(16)).toUpperCase();
}
exports.arrayToObject = function (source, options) {
var obj = options.plainObjects ? Object.create(null) : {};
for (var i = 0, il = source.length; i < il; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
exports.merge = function (target, source, options) {
if (!source) {
return target;
}
if (typeof source !== 'object') {
if (Array.isArray(target)) {
target.push(source);
}
else if (typeof target === 'object') {
target[source] = true;
}
else {
target = [target, source];
}
return target;
}
if (typeof target !== 'object') {
target = [target].concat(source);
return target;
}
if (Array.isArray(target) &&
!Array.isArray(source)) {
target = exports.arrayToObject(target, options);
}
var keys = Object.keys(source);
for (var k = 0, kl = keys.length; k < kl; ++k) {
var key = keys[k];
var value = source[key];
if (!Object.prototype.hasOwnProperty.call(target, key)) {
target[key] = value;
}
else {
target[key] = exports.merge(target[key], value, options);
}
}
return target;
};
exports.decode = function (str) {
try {
return decodeURIComponent(str.replace(/\+/g, ' '));
} catch (e) {
return str;
}
};
exports.encode = function (str) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str;
}
if (typeof str !== 'string') {
str = '' + str;
}
var out = '';
for (var i = 0, il = str.length; i < il; ++i) {
var c = str.charCodeAt(i);
if (c === 0x2D || // -
c === 0x2E || // .
c === 0x5F || // _
c === 0x7E || // ~
(c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5A) || // a-z
(c >= 0x61 && c <= 0x7A)) { // A-Z
out += str[i];
continue;
}
if (c < 0x80) {
out += internals.hexTable[c];
continue;
}
if (c < 0x800) {
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
++i;
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
}
return out;
};
exports.compact = function (obj, refs) {
if (typeof obj !== 'object' ||
obj === null) {
return obj;
}
refs = refs || [];
var lookup = refs.indexOf(obj);
if (lookup !== -1) {
return refs[lookup];
}
refs.push(obj);
if (Array.isArray(obj)) {
var compacted = [];
for (var i = 0, il = obj.length; i < il; ++i) {
if (typeof obj[i] !== 'undefined') {
compacted.push(obj[i]);
}
}
return compacted;
}
var keys = Object.keys(obj);
for (i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
obj[key] = exports.compact(obj[key], refs);
}
return obj;
};
exports.isRegExp = function (obj) {
return Object.prototype.toString.call(obj) === '[object RegExp]';
};
exports.isBuffer = function (obj) {
if (obj === null ||
typeof obj === 'undefined') {
return false;
}
return !!(obj.constructor &&
obj.constructor.isBuffer &&
obj.constructor.isBuffer(obj));
};

View File

@ -1,57 +0,0 @@
{
"name": "qs",
"version": "4.0.0",
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"homepage": "https://github.com/hapijs/qs",
"main": "lib/index.js",
"dependencies": {},
"devDependencies": {
"browserify": "^10.2.1",
"code": "1.x.x",
"lab": "5.x.x"
},
"scripts": {
"test": "lab -a code -t 100 -L",
"test-cov-html": "lab -a code -r html -o coverage.html",
"dist": "browserify --standalone Qs lib/index.js > dist/qs.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/hapijs/qs.git"
},
"keywords": [
"querystring",
"qs"
],
"license": "BSD-3-Clause",
"gitHead": "e573dd08eae6cce30d2202704691a102dfa3782a",
"bugs": {
"url": "https://github.com/hapijs/qs/issues"
},
"_id": "qs@4.0.0",
"_shasum": "c31d9b74ec27df75e543a86c78728ed8d4623607",
"_from": "qs@4.0.0",
"_npmVersion": "2.12.0",
"_nodeVersion": "0.12.4",
"_npmUser": {
"name": "nlf",
"email": "quitlahok@gmail.com"
},
"dist": {
"shasum": "c31d9b74ec27df75e543a86c78728ed8d4623607",
"tarball": "http://registry.npmjs.org/qs/-/qs-4.0.0.tgz"
},
"maintainers": [
{
"name": "nlf",
"email": "quitlahok@gmail.com"
},
{
"name": "hueniverse",
"email": "eran@hueniverse.com"
}
],
"directories": {},
"_resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
"readme": "ERROR: No README data found!"
}

View File

@ -1,478 +0,0 @@
/* eslint no-extend-native:0 */
// Load modules
var Code = require('code');
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('parse()', function () {
it('parses a simple string', function (done) {
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' });
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' });
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } });
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } });
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } });
expect(Qs.parse('foo', { strictNullHandling: true })).to.deep.equal({ foo: null });
expect(Qs.parse('foo' )).to.deep.equal({ foo: '' });
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' });
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' });
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' });
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' });
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' });
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' });
expect(Qs.parse('foo=bar&baz', { strictNullHandling: true })).to.deep.equal({ foo: 'bar', baz: null });
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' });
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World'
});
done();
});
it('allows disabling dot notation', function (done) {
expect(Qs.parse('a.b=c')).to.deep.equal({ a: { b: 'c' } });
expect(Qs.parse('a.b=c', { allowDots: false })).to.deep.equal({ 'a.b': 'c' });
done();
});
it('parses a single nested string', function (done) {
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } });
done();
});
it('parses a double nested string', function (done) {
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } });
done();
});
it('defaults to a depth of 5', function (done) {
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } });
done();
});
it('only parses one level when depth = 1', function (done) {
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } });
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } });
done();
});
it('parses a simple array', function (done) {
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
done();
});
it('parses an explicit array', function (done) {
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] });
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
done();
});
it('parses a mix of simple and explicit arrays', function (done) {
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] });
done();
});
it('parses a nested array', function (done) {
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } });
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } });
done();
});
it('allows to specify array indices', function (done) {
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] });
done();
});
it('limits specific array indices to 20', function (done) {
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] });
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } });
done();
});
it('supports keys that begin with a number', function (done) {
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } });
done();
});
it('supports encoded = signs', function (done) {
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' });
done();
});
it('is ok with url encoded strings', function (done) {
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } });
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } });
done();
});
it('allows brackets in the value', function (done) {
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' });
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' });
done();
});
it('allows empty values', function (done) {
expect(Qs.parse('')).to.deep.equal({});
expect(Qs.parse(null)).to.deep.equal({});
expect(Qs.parse(undefined)).to.deep.equal({});
done();
});
it('transforms arrays to objects', function (done) {
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', c: true } });
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', '1': 'c', x: 'y' } });
done();
});
it('transforms arrays to objects (dot notation)', function (done) {
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: 'baz' } });
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz')).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } });
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] });
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] });
expect(Qs.parse('foo.bad=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo.bad=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[]=bar&foo.bad=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb')).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
done();
});
it('can add keys to objects', function (done) {
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } });
done();
});
it('correctly prunes undefined values when converting an array to an object', function (done) {
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
done();
});
it('supports malformed uri characters', function (done) {
expect(Qs.parse('{%:%}', { strictNullHandling: true })).to.deep.equal({ '{%:%}': null });
expect(Qs.parse('{%:%}=')).to.deep.equal({ '{%:%}': '' });
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' });
done();
});
it('doesn\'t produce empty keys', function (done) {
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' });
done();
});
it('cannot access Object prototype', function (done) {
Qs.parse('constructor[prototype][bad]=bad');
Qs.parse('bad[constructor][prototype][bad]=bad');
expect(typeof Object.prototype.bad).to.equal('undefined');
done();
});
it('parses arrays of objects', function (done) {
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
done();
});
it('allows for empty strings in arrays', function (done) {
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] });
expect(Qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true })).to.deep.equal({ a: ['b', null, 'c', ''] });
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true })).to.deep.equal({ a: ['b', '', 'c', null] });
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] });
done();
});
it('compacts sparse arrays', function (done) {
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] });
done();
});
it('parses semi-parsed strings', function (done) {
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } });
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } });
done();
});
it('parses buffers correctly', function (done) {
var b = new Buffer('test');
expect(Qs.parse({ a: b })).to.deep.equal({ a: b });
done();
});
it('continues parsing when no parent is found', function (done) {
expect(Qs.parse('[]=&a=b')).to.deep.equal({ '0': '', a: 'b' });
expect(Qs.parse('[]&a=b', { strictNullHandling: true })).to.deep.equal({ '0': null, a: 'b' });
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' });
done();
});
it('does not error when parsing a very long array', function (done) {
var str = 'a[]=a';
while (Buffer.byteLength(str) < 128 * 1024) {
str += '&' + str;
}
expect(function () {
Qs.parse(str);
}).to.not.throw();
done();
});
it('should not throw when a native prototype has an enumerable property', { parallel: false }, function (done) {
Object.prototype.crash = '';
Array.prototype.crash = '';
expect(Qs.parse.bind(null, 'a=b')).to.not.throw();
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' });
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw();
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
delete Object.prototype.crash;
delete Array.prototype.crash;
done();
});
it('parses a string with an alternative string delimiter', function (done) {
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('parses a string with an alternative RegExp delimiter', function (done) {
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('does not use non-splittable objects as delimiters', function (done) {
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('allows overriding parameter limit', function (done) {
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' });
done();
});
it('allows setting the parameter limit to Infinity', function (done) {
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('allows overriding array limit', function (done) {
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } });
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } });
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
done();
});
it('allows disabling array parsing', function (done) {
expect(Qs.parse('a[0]=b&a[1]=c', { parseArrays: false })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
done();
});
it('parses an object', function (done) {
var input = {
'user[name]': { 'pop[bob]': 3 },
'user[email]': null
};
var expected = {
'user': {
'name': { 'pop[bob]': 3 },
'email': null
}
};
var result = Qs.parse(input);
expect(result).to.deep.equal(expected);
done();
});
it('parses an object in dot notation', function (done) {
var input = {
'user.name': { 'pop[bob]': 3 },
'user.email.': null
};
var expected = {
'user': {
'name': { 'pop[bob]': 3 },
'email': null
}
};
var result = Qs.parse(input);
expect(result).to.deep.equal(expected);
done();
});
it('parses an object and not child values', function (done) {
var input = {
'user[name]': { 'pop[bob]': { 'test': 3 } },
'user[email]': null
};
var expected = {
'user': {
'name': { 'pop[bob]': { 'test': 3 } },
'email': null
}
};
var result = Qs.parse(input);
expect(result).to.deep.equal(expected);
done();
});
it('does not blow up when Buffer global is missing', function (done) {
var tempBuffer = global.Buffer;
delete global.Buffer;
var result = Qs.parse('a=b&c=d');
global.Buffer = tempBuffer;
expect(result).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('does not crash when parsing circular references', function (done) {
var a = {};
a.b = a;
var parsed;
expect(function () {
parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
}).to.not.throw();
expect(parsed).to.contain('foo');
expect(parsed.foo).to.contain('bar', 'baz');
expect(parsed.foo.bar).to.equal('baz');
expect(parsed.foo.baz).to.deep.equal(a);
done();
});
it('parses plain objects correctly', function (done) {
var a = Object.create(null);
a.b = 'c';
expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
var result = Qs.parse({ a: a });
expect(result).to.contain('a');
expect(result.a).to.deep.equal(a);
done();
});
it('parses dates correctly', function (done) {
var now = new Date();
expect(Qs.parse({ a: now })).to.deep.equal({ a: now });
done();
});
it('parses regular expressions correctly', function (done) {
var re = /^test$/;
expect(Qs.parse({ a: re })).to.deep.equal({ a: re });
done();
});
it('can allow overwriting prototype properties', function (done) {
expect(Qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true })).to.deep.equal({ a: { hasOwnProperty: 'b' } }, { prototype: false });
expect(Qs.parse('hasOwnProperty=b', { allowPrototypes: true })).to.deep.equal({ hasOwnProperty: 'b' }, { prototype: false });
done();
});
it('can return plain objects', function (done) {
var expected = Object.create(null);
expected.a = Object.create(null);
expected.a.b = 'c';
expected.a.hasOwnProperty = 'd';
expect(Qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true })).to.deep.equal(expected);
expect(Qs.parse(null, { plainObjects: true })).to.deep.equal(Object.create(null));
var expectedArray = Object.create(null);
expectedArray.a = Object.create(null);
expectedArray.a['0'] = 'b';
expectedArray.a.c = 'd';
expect(Qs.parse('a[]=b&a[c]=d', { plainObjects: true })).to.deep.equal(expectedArray);
done();
});
});

View File

@ -1,259 +0,0 @@
/* eslint no-extend-native:0 */
// Load modules
var Code = require('code');
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('stringify()', function () {
it('stringifies a querystring object', function (done) {
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
expect(Qs.stringify({ a: 1 })).to.equal('a=1');
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2');
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z');
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC');
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80');
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90');
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7');
done();
});
it('stringifies a nested object', function (done) {
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
expect(Qs.stringify({ a: { b: { c: { d: 'e' } } } })).to.equal('a%5Bb%5D%5Bc%5D%5Bd%5D=e');
done();
});
it('stringifies an array value', function (done) {
expect(Qs.stringify({ a: ['b', 'c', 'd'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
done();
});
it('omits array indices when asked', function (done) {
expect(Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false })).to.equal('a=b&a=c&a=d');
done();
});
it('stringifies a nested array value', function (done) {
expect(Qs.stringify({ a: { b: ['c', 'd'] } })).to.equal('a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
done();
});
it('stringifies an object inside an array', function (done) {
expect(Qs.stringify({ a: [{ b: 'c' }] })).to.equal('a%5B0%5D%5Bb%5D=c');
expect(Qs.stringify({ a: [{ b: { c: [1] } }] })).to.equal('a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
done();
});
it('does not omit object keys when indices = false', function (done) {
expect(Qs.stringify({ a: [{ b: 'c' }] }, { indices: false })).to.equal('a%5Bb%5D=c');
done();
});
it('uses indices notation for arrays when indices=true', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { indices: true })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses indices notation for arrays when no arrayFormat is specified', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses indices notation for arrays when no arrayFormat=indices', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses repeat notation for arrays when no arrayFormat=repeat', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).to.equal('a=b&a=c');
done();
});
it('uses brackets notation for arrays when no arrayFormat=brackets', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).to.equal('a%5B%5D=b&a%5B%5D=c');
done();
});
it('stringifies a complicated object', function (done) {
expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e');
done();
});
it('stringifies an empty value', function (done) {
expect(Qs.stringify({ a: '' })).to.equal('a=');
expect(Qs.stringify({ a: null }, { strictNullHandling: true })).to.equal('a');
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b=');
expect(Qs.stringify({ a: null, b: '' }, { strictNullHandling: true })).to.equal('a&b=');
expect(Qs.stringify({ a: { b: '' } })).to.equal('a%5Bb%5D=');
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: true })).to.equal('a%5Bb%5D');
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: false })).to.equal('a%5Bb%5D=');
done();
});
it('stringifies an empty object', function (done) {
var obj = Object.create(null);
obj.a = 'b';
expect(Qs.stringify(obj)).to.equal('a=b');
done();
});
it('returns an empty string for invalid input', function (done) {
expect(Qs.stringify(undefined)).to.equal('');
expect(Qs.stringify(false)).to.equal('');
expect(Qs.stringify(null)).to.equal('');
expect(Qs.stringify('')).to.equal('');
done();
});
it('stringifies an object with an empty object as a child', function (done) {
var obj = {
a: Object.create(null)
};
obj.a.b = 'c';
expect(Qs.stringify(obj)).to.equal('a%5Bb%5D=c');
done();
});
it('drops keys with a value of undefined', function (done) {
expect(Qs.stringify({ a: undefined })).to.equal('');
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).to.equal('a%5Bc%5D');
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).to.equal('a%5Bc%5D=');
expect(Qs.stringify({ a: { b: undefined, c: '' } })).to.equal('a%5Bc%5D=');
done();
});
it('url encodes values', function (done) {
expect(Qs.stringify({ a: 'b c' })).to.equal('a=b%20c');
done();
});
it('stringifies a date', function (done) {
var now = new Date();
var str = 'a=' + encodeURIComponent(now.toISOString());
expect(Qs.stringify({ a: now })).to.equal(str);
done();
});
it('stringifies the weird object from qs', function (done) {
expect(Qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F');
done();
});
it('skips properties that are part of the object prototype', function (done) {
Object.prototype.crash = 'test';
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
delete Object.prototype.crash;
done();
});
it('stringifies boolean values', function (done) {
expect(Qs.stringify({ a: true })).to.equal('a=true');
expect(Qs.stringify({ a: { b: true } })).to.equal('a%5Bb%5D=true');
expect(Qs.stringify({ b: false })).to.equal('b=false');
expect(Qs.stringify({ b: { c: false } })).to.equal('b%5Bc%5D=false');
done();
});
it('stringifies buffer values', function (done) {
expect(Qs.stringify({ a: new Buffer('test') })).to.equal('a=test');
expect(Qs.stringify({ a: { b: new Buffer('test') } })).to.equal('a%5Bb%5D=test');
done();
});
it('stringifies an object using an alternative delimiter', function (done) {
expect(Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).to.equal('a=b;c=d');
done();
});
it('doesn\'t blow up when Buffer global is missing', function (done) {
var tempBuffer = global.Buffer;
delete global.Buffer;
expect(Qs.stringify({ a: 'b', c: 'd' })).to.equal('a=b&c=d');
global.Buffer = tempBuffer;
done();
});
it('selects properties when filter=array', function (done) {
expect(Qs.stringify({ a: 'b' }, { filter: ['a'] })).to.equal('a=b');
expect(Qs.stringify({ a: 1 }, { filter: [] })).to.equal('');
expect(Qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).to.equal('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
done();
});
it('supports custom representations when filter=function', function (done) {
var calls = 0;
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
var filterFunc = function (prefix, value) {
calls++;
if (calls === 1) {
expect(prefix).to.be.empty();
expect(value).to.equal(obj);
}
else if (prefix === 'c') {
return;
}
else if (value instanceof Date) {
expect(prefix).to.equal('e[f]');
return value.getTime();
}
return value;
};
expect(Qs.stringify(obj, { filter: filterFunc })).to.equal('a=b&e%5Bf%5D=1257894000000');
expect(calls).to.equal(5);
done();
});
});

View File

@ -1,28 +0,0 @@
// Load modules
var Code = require('code');
var Lab = require('lab');
var Utils = require('../lib/utils');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('merge()', function () {
it('can merge two objects with the same key', function (done) {
expect(Utils.merge({ a: 'b' }, { a: 'c' })).to.deep.equal({ a: ['b', 'c'] });
done();
});
});

View File

@ -1,15 +0,0 @@
#!/bin/sh
basedir=`dirname "$0"`
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mime/cli.js" "$@"
ret=$?
else
node "$basedir/../mime/cli.js" "$@"
ret=$?
fi
exit $ret

View File

@ -0,0 +1 @@
../mime/cli.js

View File

@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mime\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mime\cli.js" %*
)

0
node_modules/express/node_modules/send/node_modules/mime/cli.js generated vendored Normal file → Executable file
View File

View File

@ -36,7 +36,7 @@
"main": "mime.js",
"name": "mime",
"repository": {
"url": "git+https://github.com/broofa/node-mime.git",
"url": "https://github.com/broofa/node-mime",
"type": "git"
},
"version": "1.3.4",
@ -68,6 +68,5 @@
"tarball": "http://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
}

View File

@ -43,6 +43,5 @@
"tarball": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
"readme": "ERROR: No README data found!"
"_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
}

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