Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKat Marchán <kzm@sykosomatic.org>2015-07-24 03:17:10 +0300
committerRebecca Turner <me@re-becca.org>2015-07-24 10:22:51 +0300
commit1baa4fc8edb7e9c521949bab9dce045cde71f4d6 (patch)
treef4c7b406ef5681f67c76693cad2d04270d350fde /node_modules/request
parent90cf98097e33fcd55e552f2a9d0a8531b6371ec1 (diff)
request@2.60.0
Diffstat (limited to 'node_modules/request')
-rw-r--r--node_modules/request/CHANGELOG.md17
-rw-r--r--node_modules/request/README.md18
-rw-r--r--node_modules/request/lib/helpers.js10
-rw-r--r--node_modules/request/lib/oauth.js2
-rw-r--r--node_modules/request/lib/redirect.js3
-rw-r--r--node_modules/request/node_modules/bl/.npmignore1
-rw-r--r--node_modules/request/node_modules/bl/.travis.yml14
-rw-r--r--node_modules/request/node_modules/bl/LICENSE.md13
-rw-r--r--node_modules/request/node_modules/bl/README.md200
-rw-r--r--node_modules/request/node_modules/bl/bl.js216
-rw-r--r--node_modules/request/node_modules/bl/package.json85
-rw-r--r--node_modules/request/node_modules/bl/test/basic-test.js541
-rw-r--r--node_modules/request/node_modules/bl/test/sauce.js38
-rw-r--r--node_modules/request/node_modules/bl/test/test.js9
-rw-r--r--node_modules/request/node_modules/caseless/LICENSE28
-rw-r--r--node_modules/request/node_modules/caseless/README.md45
-rw-r--r--node_modules/request/node_modules/caseless/index.js66
-rw-r--r--node_modules/request/node_modules/caseless/package.json86
-rw-r--r--node_modules/request/node_modules/caseless/test.js40
-rw-r--r--node_modules/request/node_modules/extend/.jscs.json104
-rw-r--r--node_modules/request/node_modules/extend/.npmignore1
-rw-r--r--node_modules/request/node_modules/extend/.travis.yml44
-rw-r--r--node_modules/request/node_modules/extend/CHANGELOG.md69
-rw-r--r--node_modules/request/node_modules/extend/LICENSE23
-rw-r--r--node_modules/request/node_modules/extend/README.md62
-rw-r--r--node_modules/request/node_modules/extend/component.json32
-rw-r--r--node_modules/request/node_modules/extend/index.js86
-rw-r--r--node_modules/request/node_modules/extend/package.json96
-rw-r--r--node_modules/request/node_modules/hawk/.npmignore20
-rwxr-xr-xnode_modules/request/node_modules/hawk/.travis.yml5
-rwxr-xr-xnode_modules/request/node_modules/hawk/LICENSE28
-rwxr-xr-xnode_modules/request/node_modules/hawk/README.md634
-rw-r--r--node_modules/request/node_modules/hawk/bower.json24
-rw-r--r--node_modules/request/node_modules/hawk/component.json19
-rwxr-xr-xnode_modules/request/node_modules/hawk/example/usage.js78
-rwxr-xr-xnode_modules/request/node_modules/hawk/images/hawk.pngbin0 -> 6945 bytes
-rwxr-xr-xnode_modules/request/node_modules/hawk/images/logo.pngbin0 -> 71732 bytes
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/browser.js643
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/client.js369
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/crypto.js126
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/index.js15
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/server.js540
-rwxr-xr-xnode_modules/request/node_modules/hawk/lib/utils.js164
-rw-r--r--node_modules/request/node_modules/hawk/package.json91
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/browser.js1459
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/client.js440
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/crypto.js70
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/index.js378
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/readme.js95
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/server.js1314
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/uri.js849
-rwxr-xr-xnode_modules/request/node_modules/hawk/test/utils.js121
-rw-r--r--node_modules/request/node_modules/mime-db/HISTORY.md241
-rw-r--r--node_modules/request/node_modules/mime-db/LICENSE22
-rw-r--r--node_modules/request/node_modules/mime-db/README.md82
-rw-r--r--node_modules/request/node_modules/mime-db/db.json6424
-rw-r--r--node_modules/request/node_modules/mime-db/index.js11
-rw-r--r--node_modules/request/node_modules/mime-db/package.json118
-rw-r--r--node_modules/request/node_modules/mime-types/HISTORY.md147
-rw-r--r--node_modules/request/node_modules/mime-types/LICENSE23
-rw-r--r--node_modules/request/node_modules/mime-types/README.md103
-rw-r--r--node_modules/request/node_modules/mime-types/index.js188
-rw-r--r--node_modules/request/node_modules/mime-types/package.json107
-rw-r--r--node_modules/request/node_modules/qs/.eslintignore1
-rw-r--r--node_modules/request/node_modules/qs/.npmignore19
-rw-r--r--node_modules/request/node_modules/qs/.travis.yml6
-rw-r--r--node_modules/request/node_modules/qs/CHANGELOG.md88
-rw-r--r--node_modules/request/node_modules/qs/CONTRIBUTING.md1
-rw-r--r--node_modules/request/node_modules/qs/LICENSE28
-rw-r--r--node_modules/request/node_modules/qs/README.md317
-rw-r--r--node_modules/request/node_modules/qs/bower.json22
-rw-r--r--node_modules/request/node_modules/qs/lib/index.js15
-rw-r--r--node_modules/request/node_modules/qs/lib/parse.js186
-rw-r--r--node_modules/request/node_modules/qs/lib/stringify.js121
-rw-r--r--node_modules/request/node_modules/qs/lib/utils.js190
-rw-r--r--node_modules/request/node_modules/qs/package.json80
-rw-r--r--node_modules/request/node_modules/qs/test/parse.js478
-rw-r--r--node_modules/request/node_modules/qs/test/stringify.js259
-rw-r--r--node_modules/request/node_modules/qs/test/utils.js28
-rw-r--r--node_modules/request/node_modules/readable-stream/.npmignore5
-rw-r--r--node_modules/request/node_modules/readable-stream/.travis.yml39
-rw-r--r--node_modules/request/node_modules/readable-stream/.zuul.yml1
-rw-r--r--node_modules/request/node_modules/readable-stream/LICENSE18
-rw-r--r--node_modules/request/node_modules/readable-stream/README.md36
-rw-r--r--node_modules/request/node_modules/readable-stream/doc/stream.markdown1651
-rw-r--r--node_modules/request/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md60
-rw-r--r--node_modules/request/node_modules/readable-stream/duplex.js1
-rw-r--r--node_modules/request/node_modules/readable-stream/lib/_stream_duplex.js82
-rw-r--r--node_modules/request/node_modules/readable-stream/lib/_stream_passthrough.js27
-rw-r--r--node_modules/request/node_modules/readable-stream/lib/_stream_readable.js959
-rw-r--r--node_modules/request/node_modules/readable-stream/lib/_stream_transform.js197
-rw-r--r--node_modules/request/node_modules/readable-stream/lib/_stream_writable.js520
-rw-r--r--node_modules/request/node_modules/readable-stream/package.json98
-rw-r--r--node_modules/request/node_modules/readable-stream/passthrough.js1
-rw-r--r--node_modules/request/node_modules/readable-stream/readable.js12
-rw-r--r--node_modules/request/node_modules/readable-stream/transform.js1
-rw-r--r--node_modules/request/node_modules/readable-stream/writable.js1
-rw-r--r--node_modules/request/package.json43
-rw-r--r--node_modules/request/request.js49
99 files changed, 22490 insertions, 47 deletions
diff --git a/node_modules/request/CHANGELOG.md b/node_modules/request/CHANGELOG.md
index 6b3905edb..4cc1fcbe4 100644
--- a/node_modules/request/CHANGELOG.md
+++ b/node_modules/request/CHANGELOG.md
@@ -1,5 +1,18 @@
## Change Log
+### v2.60.0 (2015/07/21)
+- [#1687](https://github.com/request/request/pull/1687) Fix caseless bug - content-type not being set for multipart/form-data (@simov, @garymathews)
+
+### v2.59.0 (2015/07/20)
+- [#1671](https://github.com/request/request/pull/1671) Add tests and docs for using the agent, agentClass, agentOptions and forever options. Forever option defaults to using http(s).Agent in node 0.12+ (@simov)
+- [#1679](https://github.com/request/request/pull/1679) Fix - do not remove OAuth param when using OAuth realm (@simov, @jhalickman)
+- [#1668](https://github.com/request/request/pull/1668) updated dependencies (@deamme)
+- [#1656](https://github.com/request/request/pull/1656) Fix form method (@simov)
+- [#1651](https://github.com/request/request/pull/1651) Preserve HEAD method when using followAllRedirects (@simov)
+- [#1652](https://github.com/request/request/pull/1652) Update `encoding` option documentation in README.md (@daniel347x)
+- [#1650](https://github.com/request/request/pull/1650) Allow content-type overriding when using the `form` option (@simov)
+- [#1646](https://github.com/request/request/pull/1646) Clarify the nature of setting `ca` in `agentOptions` (@jeffcharles)
+
### v2.58.0 (2015/06/16)
- [#1638](https://github.com/request/request/pull/1638) Use the `extend` module to deep extend in the defaults method (@simov)
- [#1631](https://github.com/request/request/pull/1631) Move tunnel logic into separate module (@simov)
@@ -74,7 +87,7 @@
- [#1392](https://github.com/request/request/pull/1392) Improve `timeout` option description (@watson)
### v2.52.0 (2015/02/02)
-- [#1383](https://github.com/request/request/pull/1383) Add missing HTTPS options that were not being passed to tunnel (@brichard19) (@nylen, @brichard19)
+- [#1383](https://github.com/request/request/pull/1383) Add missing HTTPS options that were not being passed to tunnel (@brichard19) (@nylen)
- [#1388](https://github.com/request/request/pull/1388) Upgrade mime-types package version (@roderickhsiao)
- [#1389](https://github.com/request/request/pull/1389) Revise Setup Tunnel Function (@seanstrom)
- [#1374](https://github.com/request/request/pull/1374) Allow explicitly disabling tunneling for proxied https destinations (@nylen)
@@ -480,7 +493,7 @@
- [#121](https://github.com/request/request/pull/121) Another patch for cookie handling regression (@jhurliman)
- [#117](https://github.com/request/request/pull/117) Remove the global `i` (@3rd-Eden)
- [#110](https://github.com/request/request/pull/110) Update to Iris Couch URL (@jhs)
-- [#86](https://github.com/request/request/pull/86) Can't post binary to multipart requests (@developmentseed)
+- [#86](https://github.com/request/request/pull/86) Can't post binary to multipart requests (@kkaefer)
- [#105](https://github.com/request/request/pull/105) added test for proxy option. (@dominictarr)
- [#102](https://github.com/request/request/pull/102) Implemented cookies - closes issue 82: https://github.com/mikeal/request/issues/82 (@alessioalex)
- [#97](https://github.com/request/request/pull/97) Typo in previous pull causes TypeError in non-0.5.11 versions (@isaacs)
diff --git a/node_modules/request/README.md b/node_modules/request/README.md
index 8530d1054..b72276798 100644
--- a/node_modules/request/README.md
+++ b/node_modules/request/README.md
@@ -646,7 +646,8 @@ request.get({
It is possible to accept other certificates than those signed by generally allowed Certificate Authorities (CAs).
This can be useful, for example, when using self-signed certificates.
-To allow a different certificate, you can specify the signing CA by adding the contents of the CA's certificate file to the `agentOptions`:
+To require a different root certificate, you can specify the signing CA by adding the contents of the CA's certificate file to the `agentOptions`.
+The certificate the domain presents must be signed by the root certificate specified:
```js
request.get({
@@ -765,13 +766,17 @@ The first argument can be either a `url` or an `options` object. The only requir
---
-- `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`. Anything else **(including the default value of `undefined`)** will be passed as the [encoding](http://nodejs.org/api/buffer.html#buffer_buffer) parameter to `toString()` (meaning this is effectively `utf8` by default).
+- `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`. Anything else **(including the default value of `undefined`)** will be passed as the [encoding](http://nodejs.org/api/buffer.html#buffer_buffer) parameter to `toString()` (meaning this is effectively `utf8` by default). (**Note:** if you expect binary data, you should set `encoding: null`.)
- `gzip` - If `true`, add an `Accept-Encoding` header to request compressed content encodings from the server (if not already present) and decode supported content encodings in the response. **Note:** Automatic decoding of the response content is performed on the body data returned through `request` (both through the `request` stream and passed to the callback function) but is not performed on the `response` stream (available from the `response` event) which is the unmodified `http.IncomingMessage` object which may contain compressed data. See example below.
- `jar` - If `true` and `tough-cookie` is installed, remember cookies for future use (or define your custom cookie jar; see examples section)
---
-- `pool` - An object describing which agents to use for the request. If this option is omitted the request will use the global agent (as long as [your options allow for it](request.js#L747)). Otherwise, request will search the pool for your custom agent. If no custom agent is found, a new agent will be created and added to the pool.
+- `agent` - `http(s).Agent` instance to use
+- `agentClass` - alternatively specify your agent's class name
+- `agentOptions` - and pass its options. **Note:** for HTTPS see [tls API doc for TLS/SSL options](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback) and the [documentation above](#using-optionsagentoptions).
+- `forever` - set to `true` to use the [forever-agent](https://github.com/request/forever-agent) **Note:** Defaults to `http(s).Agent({keepAlive:true})` in node 0.12+
+- `pool` - An object describing which agents to use for the request. If this option is omitted the request will use the global agent (as long as your options allow for it). Otherwise, request will search the pool for your custom agent. If no custom agent is found, a new agent will be created and added to the pool. **Note:** `pool` is used only when the `agent` option is not specified.
- A `maxSockets` property can also be provided on the `pool` object to set the max number of sockets for all agents created (ex: `pool: {maxSockets: Infinity}`).
- Note that if you are sending multiple requests in a loop and creating
multiple new `pool` objects, `maxSockets` will not work as intended. To
@@ -782,10 +787,12 @@ The first argument can be either a `url` or an `options` object. The only requir
request to respond before aborting the request. Note that if the underlying
TCP connection cannot be established, the OS-wide TCP connection timeout will
overrule the `timeout` option ([the default in Linux is around 20 seconds](http://www.sekuda.com/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout)).
+
+---
+
- `localAddress` - Local interface to bind for network connections.
- `proxy` - An HTTP proxy to be used. Supports proxy Auth with Basic Auth, identical to support for the `url` parameter (by embedding the auth info in the `uri`)
- `strictSSL` - If `true`, requires SSL certificates be valid. **Note:** to use your own certificate authority, you need to specify an agent that was created with that CA as an option.
-- `agentOptions` - Object containing user agent options. See documentation above. **Note:** [see tls API doc for TLS/SSL options](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
- `tunnel` - controls the behavior of
[HTTP `CONNECT` tunneling](https://en.wikipedia.org/wiki/HTTP_tunnel#HTTP_CONNECT_tunneling)
as follows:
@@ -802,9 +809,6 @@ The first argument can be either a `url` or an `options` object. The only requir
---
- `time` - If `true`, the request-response cycle (including all redirects) is timed at millisecond resolution, and the result provided on the response's `elapsedTime` property.
-
----
-
- `har` - A [HAR 1.2 Request Object](http://www.softwareishard.com/blog/har-12-spec/#request), will be processed from HAR format into options overwriting matching values *(see the [HAR 1.2 section](#support-for-har-1.2) for details)*
The callback argument gets 3 arguments:
diff --git a/node_modules/request/lib/helpers.js b/node_modules/request/lib/helpers.js
index 5cc79da86..5e8594606 100644
--- a/node_modules/request/lib/helpers.js
+++ b/node_modules/request/lib/helpers.js
@@ -54,6 +54,15 @@ function copy (obj) {
return o
}
+function version () {
+ var numbers = process.version.replace('v', '').split('.')
+ return {
+ major: parseInt(numbers[0], 10),
+ minor: parseInt(numbers[1], 10),
+ patch: parseInt(numbers[2], 10)
+ }
+}
+
exports.isFunction = isFunction
exports.paramsHaveRequestBody = paramsHaveRequestBody
exports.safeStringify = safeStringify
@@ -61,4 +70,5 @@ exports.md5 = md5
exports.isReadStream = isReadStream
exports.toBase64 = toBase64
exports.copy = copy
+exports.version = version
exports.defer = deferMethod()
diff --git a/node_modules/request/lib/oauth.js b/node_modules/request/lib/oauth.js
index b0f7ab884..c24209b89 100644
--- a/node_modules/request/lib/oauth.js
+++ b/node_modules/request/lib/oauth.js
@@ -81,7 +81,7 @@ OAuth.prototype.concatParams = function (oa, sep, wrap) {
}).sort()
if (oa.realm) {
- params.splice(0, 1, 'realm')
+ params.splice(0, 0, 'realm')
}
params.push('oauth_signature')
diff --git a/node_modules/request/lib/redirect.js b/node_modules/request/lib/redirect.js
index 1d4650299..b2d0f613a 100644
--- a/node_modules/request/lib/redirect.js
+++ b/node_modules/request/lib/redirect.js
@@ -113,7 +113,8 @@ Redirect.prototype.onResponse = function (response) {
, redirectUri: redirectTo
}
)
- if (self.followAllRedirects && response.statusCode !== 401 && response.statusCode !== 307) {
+ if (self.followAllRedirects && request.method !== 'HEAD'
+ && response.statusCode !== 401 && response.statusCode !== 307) {
request.method = 'GET'
}
// request.method = 'GET' // Force all redirects to use GET || commented out fixes #215
diff --git a/node_modules/request/node_modules/bl/.npmignore b/node_modules/request/node_modules/bl/.npmignore
new file mode 100644
index 000000000..40b878db5
--- /dev/null
+++ b/node_modules/request/node_modules/bl/.npmignore
@@ -0,0 +1 @@
+node_modules/ \ No newline at end of file
diff --git a/node_modules/request/node_modules/bl/.travis.yml b/node_modules/request/node_modules/bl/.travis.yml
new file mode 100644
index 000000000..81c081418
--- /dev/null
+++ b/node_modules/request/node_modules/bl/.travis.yml
@@ -0,0 +1,14 @@
+language: node_js
+before_install:
+ - curl --location http://git.io/1OcIZA | bash -s
+node_js:
+ - 0.8
+ - 0.10
+ - 0.11
+branches:
+ only:
+ - master
+notifications:
+ email:
+ - rod@vagg.org
+script: npm test
diff --git a/node_modules/request/node_modules/bl/LICENSE.md b/node_modules/request/node_modules/bl/LICENSE.md
new file mode 100644
index 000000000..ccb24797c
--- /dev/null
+++ b/node_modules/request/node_modules/bl/LICENSE.md
@@ -0,0 +1,13 @@
+The MIT License (MIT)
+=====================
+
+Copyright (c) 2014 bl contributors
+----------------------------------
+
+*bl contributors listed at <https://github.com/rvagg/bl#contributors>*
+
+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.
diff --git a/node_modules/request/node_modules/bl/README.md b/node_modules/request/node_modules/bl/README.md
new file mode 100644
index 000000000..4d87866aa
--- /dev/null
+++ b/node_modules/request/node_modules/bl/README.md
@@ -0,0 +1,200 @@
+# bl *(BufferList)*
+
+[![Build Status](https://travis-ci.org/rvagg/bl.svg?branch=master)](https://travis-ci.org/rvagg/bl)
+
+**A Node.js Buffer list collector, reader and streamer thingy.**
+
+[![NPM](https://nodei.co/npm/bl.png?downloads=true&downloadRank=true)](https://nodei.co/npm/bl/)
+[![NPM](https://nodei.co/npm-dl/bl.png?months=6&height=3)](https://nodei.co/npm/bl/)
+
+**bl** is a storage object for collections of Node Buffers, exposing them with the main Buffer readable API. Also works as a duplex stream so you can collect buffers from a stream that emits them and emit buffers to a stream that consumes them!
+
+The original buffers are kept intact and copies are only done as necessary. Any reads that require the use of a single original buffer will return a slice of that buffer only (which references the same memory as the original buffer). Reads that span buffers perform concatenation as required and return the results transparently.
+
+```js
+const BufferList = require('bl')
+
+var bl = new BufferList()
+bl.append(new Buffer('abcd'))
+bl.append(new Buffer('efg'))
+bl.append('hi') // bl will also accept & convert Strings
+bl.append(new Buffer('j'))
+bl.append(new Buffer([ 0x3, 0x4 ]))
+
+console.log(bl.length) // 12
+
+console.log(bl.slice(0, 10).toString('ascii')) // 'abcdefghij'
+console.log(bl.slice(3, 10).toString('ascii')) // 'defghij'
+console.log(bl.slice(3, 6).toString('ascii')) // 'def'
+console.log(bl.slice(3, 8).toString('ascii')) // 'defgh'
+console.log(bl.slice(5, 10).toString('ascii')) // 'fghij'
+
+// or just use toString!
+console.log(bl.toString()) // 'abcdefghij\u0003\u0004'
+console.log(bl.toString('ascii', 3, 8)) // 'defgh'
+console.log(bl.toString('ascii', 5, 10)) // 'fghij'
+
+// other standard Buffer readables
+console.log(bl.readUInt16BE(10)) // 0x0304
+console.log(bl.readUInt16LE(10)) // 0x0403
+```
+
+Give it a callback in the constructor and use it just like **[concat-stream](https://github.com/maxogden/node-concat-stream)**:
+
+```js
+const bl = require('bl')
+ , fs = require('fs')
+
+fs.createReadStream('README.md')
+ .pipe(bl(function (err, data) { // note 'new' isn't strictly required
+ // `data` is a complete Buffer object containing the full data
+ console.log(data.toString())
+ }))
+```
+
+Note that when you use the *callback* method like this, the resulting `data` parameter is a concatenation of all `Buffer` objects in the list. If you want to avoid the overhead of this concatenation (in cases of extreme performance consciousness), then avoid the *callback* method and just listen to `'end'` instead, like a standard Stream.
+
+Or to fetch a URL using [hyperquest](https://github.com/substack/hyperquest) (should work with [request](http://github.com/mikeal/request) and even plain Node http too!):
+```js
+const hyperquest = require('hyperquest')
+ , bl = require('bl')
+ , url = 'https://raw.github.com/rvagg/bl/master/README.md'
+
+hyperquest(url).pipe(bl(function (err, data) {
+ console.log(data.toString())
+}))
+```
+
+Or, use it as a readable stream to recompose a list of Buffers to an output source:
+
+```js
+const BufferList = require('bl')
+ , fs = require('fs')
+
+var bl = new BufferList()
+bl.append(new Buffer('abcd'))
+bl.append(new Buffer('efg'))
+bl.append(new Buffer('hi'))
+bl.append(new Buffer('j'))
+
+bl.pipe(fs.createWriteStream('gibberish.txt'))
+```
+
+## API
+
+ * <a href="#ctor"><code><b>new BufferList([ callback ])</b></code></a>
+ * <a href="#length"><code>bl.<b>length</b></code></a>
+ * <a href="#append"><code>bl.<b>append(buffer)</b></code></a>
+ * <a href="#get"><code>bl.<b>get(index)</b></code></a>
+ * <a href="#slice"><code>bl.<b>slice([ start[, end ] ])</b></code></a>
+ * <a href="#copy"><code>bl.<b>copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])</b></code></a>
+ * <a href="#duplicate"><code>bl.<b>duplicate()</b></code></a>
+ * <a href="#consume"><code>bl.<b>consume(bytes)</b></code></a>
+ * <a href="#toString"><code>bl.<b>toString([encoding, [ start, [ end ]]])</b></code></a>
+ * <a href="#readXX"><code>bl.<b>readDoubleBE()</b></code>, <code>bl.<b>readDoubleLE()</b></code>, <code>bl.<b>readFloatBE()</b></code>, <code>bl.<b>readFloatLE()</b></code>, <code>bl.<b>readInt32BE()</b></code>, <code>bl.<b>readInt32LE()</b></code>, <code>bl.<b>readUInt32BE()</b></code>, <code>bl.<b>readUInt32LE()</b></code>, <code>bl.<b>readInt16BE()</b></code>, <code>bl.<b>readInt16LE()</b></code>, <code>bl.<b>readUInt16BE()</b></code>, <code>bl.<b>readUInt16LE()</b></code>, <code>bl.<b>readInt8()</b></code>, <code>bl.<b>readUInt8()</b></code></a>
+ * <a href="#streams">Streams</a>
+
+--------------------------------------------------------
+<a name="ctor"></a>
+### new BufferList([ callback | buffer | buffer array ])
+The constructor takes an optional callback, if supplied, the callback will be called with an error argument followed by a reference to the **bl** instance, when `bl.end()` is called (i.e. from a piped stream). This is a convenient method of collecting the entire contents of a stream, particularly when the stream is *chunky*, such as a network stream.
+
+Normally, no arguments are required for the constructor, but you can initialise the list by passing in a single `Buffer` object or an array of `Buffer` object.
+
+`new` is not strictly required, if you don't instantiate a new object, it will be done automatically for you so you can create a new instance simply with:
+
+```js
+var bl = require('bl')
+var myinstance = bl()
+
+// equivilant to:
+
+var BufferList = require('bl')
+var myinstance = new BufferList()
+```
+
+--------------------------------------------------------
+<a name="length"></a>
+### bl.length
+Get the length of the list in bytes. This is the sum of the lengths of all of the buffers contained in the list, minus any initial offset for a semi-consumed buffer at the beginning. Should accurately represent the total number of bytes that can be read from the list.
+
+--------------------------------------------------------
+<a name="append"></a>
+### bl.append(buffer)
+`append(buffer)` adds an additional buffer or BufferList to the internal list.
+
+--------------------------------------------------------
+<a name="get"></a>
+### bl.get(index)
+`get()` will return the byte at the specified index.
+
+--------------------------------------------------------
+<a name="slice"></a>
+### bl.slice([ start, [ end ] ])
+`slice()` returns a new `Buffer` object containing the bytes within the range specified. Both `start` and `end` are optional and will default to the beginning and end of the list respectively.
+
+If the requested range spans a single internal buffer then a slice of that buffer will be returned which shares the original memory range of that Buffer. If the range spans multiple buffers then copy operations will likely occur to give you a uniform Buffer.
+
+--------------------------------------------------------
+<a name="copy"></a>
+### bl.copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])
+`copy()` copies the content of the list in the `dest` buffer, starting from `destStart` and containing the bytes within the range specified with `srcStart` to `srcEnd`. `destStart`, `start` and `end` are optional and will default to the beginning of the `dest` buffer, and the beginning and end of the list respectively.
+
+--------------------------------------------------------
+<a name="duplicate"></a>
+### bl.duplicate()
+`duplicate()` performs a **shallow-copy** of the list. The internal Buffers remains the same, so if you change the underlying Buffers, the change will be reflected in both the original and the duplicate. This method is needed if you want to call `consume()` or `pipe()` and still keep the original list.Example:
+
+```js
+var bl = new BufferList()
+
+bl.append('hello')
+bl.append(' world')
+bl.append('\n')
+
+bl.duplicate().pipe(process.stdout, { end: false })
+
+console.log(bl.toString())
+```
+
+--------------------------------------------------------
+<a name="consume"></a>
+### bl.consume(bytes)
+`consume()` will shift bytes *off the start of the list*. The number of bytes consumed don't need to line up with the sizes of the internal Buffers&mdash;initial offsets will be calculated accordingly in order to give you a consistent view of the data.
+
+--------------------------------------------------------
+<a name="toString"></a>
+### bl.toString([encoding, [ start, [ end ]]])
+`toString()` will return a string representation of the buffer. The optional `start` and `end` arguments are passed on to `slice()`, while the `encoding` is passed on to `toString()` of the resulting Buffer. See the [Buffer#toString()](http://nodejs.org/docs/latest/api/buffer.html#buffer_buf_tostring_encoding_start_end) documentation for more information.
+
+--------------------------------------------------------
+<a name="readXX"></a>
+### bl.readDoubleBE(), bl.readDoubleLE(), bl.readFloatBE(), bl.readFloatLE(), bl.readInt32BE(), bl.readInt32LE(), bl.readUInt32BE(), bl.readUInt32LE(), bl.readInt16BE(), bl.readInt16LE(), bl.readUInt16BE(), bl.readUInt16LE(), bl.readInt8(), bl.readUInt8()
+
+All of the standard byte-reading methods of the `Buffer` interface are implemented and will operate across internal Buffer boundaries transparently.
+
+See the <b><code>[Buffer](http://nodejs.org/docs/latest/api/buffer.html)</code></b> documentation for how these work.
+
+--------------------------------------------------------
+<a name="streams"></a>
+### Streams
+**bl** is a Node **[Duplex Stream](http://nodejs.org/docs/latest/api/stream.html#stream_class_stream_duplex)**, so it can be read from and written to like a standard Node stream. You can also `pipe()` to and from a **bl** instance.
+
+--------------------------------------------------------
+
+## Contributors
+
+**bl** is brought to you by the following hackers:
+
+ * [Rod Vagg](https://github.com/rvagg)
+ * [Matteo Collina](https://github.com/mcollina)
+ * [Jarett Cruger](https://github.com/jcrugzz)
+
+=======
+
+<a name="license"></a>
+## License &amp; copyright
+
+Copyright (c) 2013-2014 bl contributors (listed above).
+
+bl is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.
diff --git a/node_modules/request/node_modules/bl/bl.js b/node_modules/request/node_modules/bl/bl.js
new file mode 100644
index 000000000..7a2f99788
--- /dev/null
+++ b/node_modules/request/node_modules/bl/bl.js
@@ -0,0 +1,216 @@
+var DuplexStream = require('readable-stream/duplex')
+ , util = require('util')
+
+function BufferList (callback) {
+ if (!(this instanceof BufferList))
+ return new BufferList(callback)
+
+ this._bufs = []
+ this.length = 0
+
+ if (typeof callback == 'function') {
+ this._callback = callback
+
+ var piper = function (err) {
+ if (this._callback) {
+ this._callback(err)
+ this._callback = null
+ }
+ }.bind(this)
+
+ this.on('pipe', function (src) {
+ src.on('error', piper)
+ })
+ this.on('unpipe', function (src) {
+ src.removeListener('error', piper)
+ })
+ }
+ else if (Buffer.isBuffer(callback))
+ this.append(callback)
+ else if (Array.isArray(callback)) {
+ callback.forEach(function (b) {
+ Buffer.isBuffer(b) && this.append(b)
+ }.bind(this))
+ }
+
+ DuplexStream.call(this)
+}
+
+util.inherits(BufferList, DuplexStream)
+
+BufferList.prototype._offset = function (offset) {
+ var tot = 0, i = 0, _t
+ for (; i < this._bufs.length; i++) {
+ _t = tot + this._bufs[i].length
+ if (offset < _t)
+ return [ i, offset - tot ]
+ tot = _t
+ }
+}
+
+BufferList.prototype.append = function (buf) {
+ var isBuffer = Buffer.isBuffer(buf) ||
+ buf instanceof BufferList
+
+ this._bufs.push(isBuffer ? buf : new Buffer(buf))
+ this.length += buf.length
+ return this
+}
+
+BufferList.prototype._write = function (buf, encoding, callback) {
+ this.append(buf)
+ if (callback)
+ callback()
+}
+
+BufferList.prototype._read = function (size) {
+ if (!this.length)
+ return this.push(null)
+ size = Math.min(size, this.length)
+ this.push(this.slice(0, size))
+ this.consume(size)
+}
+
+BufferList.prototype.end = function (chunk) {
+ DuplexStream.prototype.end.call(this, chunk)
+
+ if (this._callback) {
+ this._callback(null, this.slice())
+ this._callback = null
+ }
+}
+
+BufferList.prototype.get = function (index) {
+ return this.slice(index, index + 1)[0]
+}
+
+BufferList.prototype.slice = function (start, end) {
+ return this.copy(null, 0, start, end)
+}
+
+BufferList.prototype.copy = function (dst, dstStart, srcStart, srcEnd) {
+ if (typeof srcStart != 'number' || srcStart < 0)
+ srcStart = 0
+ if (typeof srcEnd != 'number' || srcEnd > this.length)
+ srcEnd = this.length
+ if (srcStart >= this.length)
+ return dst || new Buffer(0)
+ if (srcEnd <= 0)
+ return dst || new Buffer(0)
+
+ var copy = !!dst
+ , off = this._offset(srcStart)
+ , len = srcEnd - srcStart
+ , bytes = len
+ , bufoff = (copy && dstStart) || 0
+ , start = off[1]
+ , l
+ , i
+
+ // copy/slice everything
+ if (srcStart === 0 && srcEnd == this.length) {
+ if (!copy) // slice, just return a full concat
+ return Buffer.concat(this._bufs)
+
+ // copy, need to copy individual buffers
+ for (i = 0; i < this._bufs.length; i++) {
+ this._bufs[i].copy(dst, bufoff)
+ bufoff += this._bufs[i].length
+ }
+
+ return dst
+ }
+
+ // easy, cheap case where it's a subset of one of the buffers
+ if (bytes <= this._bufs[off[0]].length - start) {
+ return copy
+ ? this._bufs[off[0]].copy(dst, dstStart, start, start + bytes)
+ : this._bufs[off[0]].slice(start, start + bytes)
+ }
+
+ if (!copy) // a slice, we need something to copy in to
+ dst = new Buffer(len)
+
+ for (i = off[0]; i < this._bufs.length; i++) {
+ l = this._bufs[i].length - start
+
+ if (bytes > l) {
+ this._bufs[i].copy(dst, bufoff, start)
+ } else {
+ this._bufs[i].copy(dst, bufoff, start, start + bytes)
+ break
+ }
+
+ bufoff += l
+ bytes -= l
+
+ if (start)
+ start = 0
+ }
+
+ return dst
+}
+
+BufferList.prototype.toString = function (encoding, start, end) {
+ return this.slice(start, end).toString(encoding)
+}
+
+BufferList.prototype.consume = function (bytes) {
+ while (this._bufs.length) {
+ if (bytes > this._bufs[0].length) {
+ bytes -= this._bufs[0].length
+ this.length -= this._bufs[0].length
+ this._bufs.shift()
+ } else {
+ this._bufs[0] = this._bufs[0].slice(bytes)
+ this.length -= bytes
+ break
+ }
+ }
+ return this
+}
+
+BufferList.prototype.duplicate = function () {
+ var i = 0
+ , copy = new BufferList()
+
+ for (; i < this._bufs.length; i++)
+ copy.append(this._bufs[i])
+
+ return copy
+}
+
+BufferList.prototype.destroy = function () {
+ this._bufs.length = 0;
+ this.length = 0;
+ this.push(null);
+}
+
+;(function () {
+ var methods = {
+ 'readDoubleBE' : 8
+ , 'readDoubleLE' : 8
+ , 'readFloatBE' : 4
+ , 'readFloatLE' : 4
+ , 'readInt32BE' : 4
+ , 'readInt32LE' : 4
+ , 'readUInt32BE' : 4
+ , 'readUInt32LE' : 4
+ , 'readInt16BE' : 2
+ , 'readInt16LE' : 2
+ , 'readUInt16BE' : 2
+ , 'readUInt16LE' : 2
+ , 'readInt8' : 1
+ , 'readUInt8' : 1
+ }
+
+ for (var m in methods) {
+ (function (m) {
+ BufferList.prototype[m] = function (offset) {
+ return this.slice(offset, offset + methods[m])[m](0)
+ }
+ }(m))
+ }
+}())
+
+module.exports = BufferList
diff --git a/node_modules/request/node_modules/bl/package.json b/node_modules/request/node_modules/bl/package.json
new file mode 100644
index 000000000..d2f8a80ba
--- /dev/null
+++ b/node_modules/request/node_modules/bl/package.json
@@ -0,0 +1,85 @@
+{
+ "_args": [
+ [
+ "bl@~1.0.0",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "bl@>=1.0.0 <1.1.0",
+ "_id": "bl@1.0.0",
+ "_inCache": true,
+ "_location": "/request/bl",
+ "_nodeVersion": "2.0.1-nightly20150618d2e4e03444",
+ "_npmUser": {
+ "email": "rod@vagg.org",
+ "name": "rvagg"
+ },
+ "_npmVersion": "2.9.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "bl",
+ "raw": "bl@~1.0.0",
+ "rawSpec": "~1.0.0",
+ "scope": null,
+ "spec": ">=1.0.0 <1.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
+ "_shasum": "ada9a8a89a6d7ac60862f7dec7db207873e0c3f5",
+ "_shrinkwrap": null,
+ "_spec": "bl@~1.0.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "authors": [
+ "Jarett Cruger <jcrugzz@gmail.com> (https://github.com/jcrugzz)",
+ "Matteo Collina <matteo.collina@gmail.com> (https://github.com/mcollina)",
+ "Rod Vagg <rod@vagg.org> (https://github.com/rvagg)"
+ ],
+ "bugs": {
+ "url": "https://github.com/rvagg/bl/issues"
+ },
+ "dependencies": {
+ "readable-stream": "~2.0.0"
+ },
+ "description": "Buffer List: collect buffers and access with a standard readable Buffer interface, streamable too!",
+ "devDependencies": {
+ "brtapsauce": "~0.3.0",
+ "faucet": "~0.0.1",
+ "hash_file": "~0.1.1",
+ "tape": "~2.12.3"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "ada9a8a89a6d7ac60862f7dec7db207873e0c3f5",
+ "tarball": "http://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
+ },
+ "gitHead": "1794938be6697a6d1e02cd942a4eea59b353347a",
+ "homepage": "https://github.com/rvagg/bl",
+ "keywords": [
+ "awesomesauce",
+ "buffer",
+ "buffers",
+ "stream"
+ ],
+ "license": "MIT",
+ "main": "bl.js",
+ "maintainers": [
+ {
+ "name": "rvagg",
+ "email": "rod@vagg.org"
+ }
+ ],
+ "name": "bl",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/rvagg/bl.git"
+ },
+ "scripts": {
+ "test": "node test/test.js | faucet",
+ "test-local": "brtapsauce-local test/basic-test.js"
+ },
+ "version": "1.0.0"
+}
diff --git a/node_modules/request/node_modules/bl/test/basic-test.js b/node_modules/request/node_modules/bl/test/basic-test.js
new file mode 100644
index 000000000..75116a30f
--- /dev/null
+++ b/node_modules/request/node_modules/bl/test/basic-test.js
@@ -0,0 +1,541 @@
+var tape = require('tape')
+ , crypto = require('crypto')
+ , fs = require('fs')
+ , hash = require('hash_file')
+ , BufferList = require('../')
+
+ , encodings =
+ ('hex utf8 utf-8 ascii binary base64'
+ + (process.browser ? '' : ' ucs2 ucs-2 utf16le utf-16le')).split(' ')
+
+tape('single bytes from single buffer', function (t) {
+ var bl = new BufferList()
+ bl.append(new Buffer('abcd'))
+
+ t.equal(bl.length, 4)
+
+ t.equal(bl.get(0), 97)
+ t.equal(bl.get(1), 98)
+ t.equal(bl.get(2), 99)
+ t.equal(bl.get(3), 100)
+
+ t.end()
+})
+
+tape('single bytes from multiple buffers', function (t) {
+ var bl = new BufferList()
+ bl.append(new Buffer('abcd'))
+ bl.append(new Buffer('efg'))
+ bl.append(new Buffer('hi'))
+ bl.append(new Buffer('j'))
+
+ t.equal(bl.length, 10)
+
+ t.equal(bl.get(0), 97)
+ t.equal(bl.get(1), 98)
+ t.equal(bl.get(2), 99)
+ t.equal(bl.get(3), 100)
+ t.equal(bl.get(4), 101)
+ t.equal(bl.get(5), 102)
+ t.equal(bl.get(6), 103)
+ t.equal(bl.get(7), 104)
+ t.equal(bl.get(8), 105)
+ t.equal(bl.get(9), 106)
+ t.end()
+})
+
+tape('multi bytes from single buffer', function (t) {
+ var bl = new BufferList()
+ bl.append(new Buffer('abcd'))
+
+ t.equal(bl.length, 4)
+
+ t.equal(bl.slice(0, 4).toString('ascii'), 'abcd')
+ t.equal(bl.slice(0, 3).toString('ascii'), 'abc')
+ t.equal(bl.slice(1, 4).toString('ascii'), 'bcd')
+
+ t.end()
+})
+
+tape('multiple bytes from multiple buffers', function (t) {
+ var bl = new BufferList()
+
+ bl.append(new Buffer('abcd'))
+ bl.append(new Buffer('efg'))
+ bl.append(new Buffer('hi'))
+ bl.append(new Buffer('j'))
+
+ t.equal(bl.length, 10)
+
+ t.equal(bl.slice(0, 10).toString('ascii'), 'abcdefghij')
+ t.equal(bl.slice(3, 10).toString('ascii'), 'defghij')
+ t.equal(bl.slice(3, 6).toString('ascii'), 'def')
+ t.equal(bl.slice(3, 8).toString('ascii'), 'defgh')
+ t.equal(bl.slice(5, 10).toString('ascii'), 'fghij')
+
+ t.end()
+})
+
+tape('multiple bytes from multiple buffer lists', function (t) {
+ var bl = new BufferList()
+
+ bl.append(new BufferList([new Buffer('abcd'), new Buffer('efg')]))
+ bl.append(new BufferList([new Buffer('hi'), new Buffer('j')]))
+
+ t.equal(bl.length, 10)
+
+ t.equal(bl.slice(0, 10).toString('ascii'), 'abcdefghij')
+ t.equal(bl.slice(3, 10).toString('ascii'), 'defghij')
+ t.equal(bl.slice(3, 6).toString('ascii'), 'def')
+ t.equal(bl.slice(3, 8).toString('ascii'), 'defgh')
+ t.equal(bl.slice(5, 10).toString('ascii'), 'fghij')
+
+ t.end()
+})
+
+tape('consuming from multiple buffers', function (t) {
+ var bl = new BufferList()
+
+ bl.append(new Buffer('abcd'))
+ bl.append(new Buffer('efg'))
+ bl.append(new Buffer('hi'))
+ bl.append(new Buffer('j'))
+
+ t.equal(bl.length, 10)
+
+ t.equal(bl.slice(0, 10).toString('ascii'), 'abcdefghij')
+
+ bl.consume(3)
+ t.equal(bl.length, 7)
+ t.equal(bl.slice(0, 7).toString('ascii'), 'defghij')
+
+ bl.consume(2)
+ t.equal(bl.length, 5)
+ t.equal(bl.slice(0, 5).toString('ascii'), 'fghij')
+
+ bl.consume(1)
+ t.equal(bl.length, 4)
+ t.equal(bl.slice(0, 4).toString('ascii'), 'ghij')
+
+ bl.consume(1)
+ t.equal(bl.length, 3)
+ t.equal(bl.slice(0, 3).toString('ascii'), 'hij')
+
+ bl.consume(2)
+ t.equal(bl.length, 1)
+ t.equal(bl.slice(0, 1).toString('ascii'), 'j')
+
+ t.end()
+})
+
+tape('test readUInt8 / readInt8', function (t) {
+ var buf1 = new Buffer(1)
+ , buf2 = new Buffer(3)
+ , buf3 = new Buffer(3)
+ , bl = new BufferList()
+
+ buf2[1] = 0x3
+ buf2[2] = 0x4
+ buf3[0] = 0x23
+ buf3[1] = 0x42
+
+ bl.append(buf1)
+ bl.append(buf2)
+ bl.append(buf3)
+
+ t.equal(bl.readUInt8(2), 0x3)
+ t.equal(bl.readInt8(2), 0x3)
+ t.equal(bl.readUInt8(3), 0x4)
+ t.equal(bl.readInt8(3), 0x4)
+ t.equal(bl.readUInt8(4), 0x23)
+ t.equal(bl.readInt8(4), 0x23)
+ t.equal(bl.readUInt8(5), 0x42)
+ t.equal(bl.readInt8(5), 0x42)
+ t.end()
+})
+
+tape('test readUInt16LE / readUInt16BE / readInt16LE / readInt16BE', function (t) {
+ var buf1 = new Buffer(1)
+ , buf2 = new Buffer(3)
+ , buf3 = new Buffer(3)
+ , bl = new BufferList()
+
+ buf2[1] = 0x3
+ buf2[2] = 0x4
+ buf3[0] = 0x23
+ buf3[1] = 0x42
+
+ bl.append(buf1)
+ bl.append(buf2)
+ bl.append(buf3)
+
+ t.equal(bl.readUInt16BE(2), 0x0304)
+ t.equal(bl.readUInt16LE(2), 0x0403)
+ t.equal(bl.readInt16BE(2), 0x0304)
+ t.equal(bl.readInt16LE(2), 0x0403)
+ t.equal(bl.readUInt16BE(3), 0x0423)
+ t.equal(bl.readUInt16LE(3), 0x2304)
+ t.equal(bl.readInt16BE(3), 0x0423)
+ t.equal(bl.readInt16LE(3), 0x2304)
+ t.equal(bl.readUInt16BE(4), 0x2342)
+ t.equal(bl.readUInt16LE(4), 0x4223)
+ t.equal(bl.readInt16BE(4), 0x2342)
+ t.equal(bl.readInt16LE(4), 0x4223)
+ t.end()
+})
+
+tape('test readUInt32LE / readUInt32BE / readInt32LE / readInt32BE', function (t) {
+ var buf1 = new Buffer(1)
+ , buf2 = new Buffer(3)
+ , buf3 = new Buffer(3)
+ , bl = new BufferList()
+
+ buf2[1] = 0x3
+ buf2[2] = 0x4
+ buf3[0] = 0x23
+ buf3[1] = 0x42
+
+ bl.append(buf1)
+ bl.append(buf2)
+ bl.append(buf3)
+
+ t.equal(bl.readUInt32BE(2), 0x03042342)
+ t.equal(bl.readUInt32LE(2), 0x42230403)
+ t.equal(bl.readInt32BE(2), 0x03042342)
+ t.equal(bl.readInt32LE(2), 0x42230403)
+ t.end()
+})
+
+tape('test readFloatLE / readFloatBE', function (t) {
+ var buf1 = new Buffer(1)
+ , buf2 = new Buffer(3)
+ , buf3 = new Buffer(3)
+ , bl = new BufferList()
+
+ buf2[1] = 0x00
+ buf2[2] = 0x00
+ buf3[0] = 0x80
+ buf3[1] = 0x3f
+
+ bl.append(buf1)
+ bl.append(buf2)
+ bl.append(buf3)
+
+ t.equal(bl.readFloatLE(2), 0x01)
+ t.end()
+})
+
+tape('test readDoubleLE / readDoubleBE', function (t) {
+ var buf1 = new Buffer(1)
+ , buf2 = new Buffer(3)
+ , buf3 = new Buffer(10)
+ , bl = new BufferList()
+
+ buf2[1] = 0x55
+ buf2[2] = 0x55
+ buf3[0] = 0x55
+ buf3[1] = 0x55
+ buf3[2] = 0x55
+ buf3[3] = 0x55
+ buf3[4] = 0xd5
+ buf3[5] = 0x3f
+
+ bl.append(buf1)
+ bl.append(buf2)
+ bl.append(buf3)
+
+ t.equal(bl.readDoubleLE(2), 0.3333333333333333)
+ t.end()
+})
+
+tape('test toString', function (t) {
+ var bl = new BufferList()
+
+ bl.append(new Buffer('abcd'))
+ bl.append(new Buffer('efg'))
+ bl.append(new Buffer('hi'))
+ bl.append(new Buffer('j'))
+
+ t.equal(bl.toString('ascii', 0, 10), 'abcdefghij')
+ t.equal(bl.toString('ascii', 3, 10), 'defghij')
+ t.equal(bl.toString('ascii', 3, 6), 'def')
+ t.equal(bl.toString('ascii', 3, 8), 'defgh')
+ t.equal(bl.toString('ascii', 5, 10), 'fghij')
+
+ t.end()
+})
+
+tape('test toString encoding', function (t) {
+ var bl = new BufferList()
+ , b = new Buffer('abcdefghij\xff\x00')
+
+ bl.append(new Buffer('abcd'))
+ bl.append(new Buffer('efg'))
+ bl.append(new Buffer('hi'))
+ bl.append(new Buffer('j'))
+ bl.append(new Buffer('\xff\x00'))
+
+ encodings.forEach(function (enc) {
+ t.equal(bl.toString(enc), b.toString(enc), enc)
+ })
+
+ t.end()
+})
+
+!process.browser && tape('test stream', function (t) {
+ var random = crypto.randomBytes(65534)
+ , rndhash = hash(random, 'md5')
+ , md5sum = crypto.createHash('md5')
+ , bl = new BufferList(function (err, buf) {
+ t.ok(Buffer.isBuffer(buf))
+ t.ok(err === null)
+ t.equal(rndhash, hash(bl.slice(), 'md5'))
+ t.equal(rndhash, hash(buf, 'md5'))
+
+ bl.pipe(fs.createWriteStream('/tmp/bl_test_rnd_out.dat'))
+ .on('close', function () {
+ var s = fs.createReadStream('/tmp/bl_test_rnd_out.dat')
+ s.on('data', md5sum.update.bind(md5sum))
+ s.on('end', function() {
+ t.equal(rndhash, md5sum.digest('hex'), 'woohoo! correct hash!')
+ t.end()
+ })
+ })
+
+ })
+
+ fs.writeFileSync('/tmp/bl_test_rnd.dat', random)
+ fs.createReadStream('/tmp/bl_test_rnd.dat').pipe(bl)
+})
+
+tape('instantiation with Buffer', function (t) {
+ var buf = crypto.randomBytes(1024)
+ , buf2 = crypto.randomBytes(1024)
+ , b = BufferList(buf)
+
+ t.equal(buf.toString('hex'), b.slice().toString('hex'), 'same buffer')
+ b = BufferList([ buf, buf2 ])
+ t.equal(b.slice().toString('hex'), Buffer.concat([ buf, buf2 ]).toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('test String appendage', function (t) {
+ var bl = new BufferList()
+ , b = new Buffer('abcdefghij\xff\x00')
+
+ bl.append('abcd')
+ bl.append('efg')
+ bl.append('hi')
+ bl.append('j')
+ bl.append('\xff\x00')
+
+ encodings.forEach(function (enc) {
+ t.equal(bl.toString(enc), b.toString(enc))
+ })
+
+ t.end()
+})
+
+tape('write nothing, should get empty buffer', function (t) {
+ t.plan(3)
+ BufferList(function (err, data) {
+ t.notOk(err, 'no error')
+ t.ok(Buffer.isBuffer(data), 'got a buffer')
+ t.equal(0, data.length, 'got a zero-length buffer')
+ t.end()
+ }).end()
+})
+
+tape('unicode string', function (t) {
+ t.plan(2)
+ var inp1 = '\u2600'
+ , inp2 = '\u2603'
+ , exp = inp1 + ' and ' + inp2
+ , bl = BufferList()
+ bl.write(inp1)
+ bl.write(' and ')
+ bl.write(inp2)
+ t.equal(exp, bl.toString())
+ t.equal(new Buffer(exp).toString('hex'), bl.toString('hex'))
+})
+
+tape('should emit finish', function (t) {
+ var source = BufferList()
+ , dest = BufferList()
+
+ source.write('hello')
+ source.pipe(dest)
+
+ dest.on('finish', function () {
+ t.equal(dest.toString('utf8'), 'hello')
+ t.end()
+ })
+})
+
+tape('basic copy', function (t) {
+ var buf = crypto.randomBytes(1024)
+ , buf2 = new Buffer(1024)
+ , b = BufferList(buf)
+
+ b.copy(buf2)
+ t.equal(b.slice().toString('hex'), buf2.toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('copy after many appends', function (t) {
+ var buf = crypto.randomBytes(512)
+ , buf2 = new Buffer(1024)
+ , b = BufferList(buf)
+
+ b.append(buf)
+ b.copy(buf2)
+ t.equal(b.slice().toString('hex'), buf2.toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('copy at a precise position', function (t) {
+ var buf = crypto.randomBytes(1004)
+ , buf2 = new Buffer(1024)
+ , b = BufferList(buf)
+
+ b.copy(buf2, 20)
+ t.equal(b.slice().toString('hex'), buf2.slice(20).toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('copy starting from a precise location', function (t) {
+ var buf = crypto.randomBytes(10)
+ , buf2 = new Buffer(5)
+ , b = BufferList(buf)
+
+ b.copy(buf2, 0, 5)
+ t.equal(b.slice(5).toString('hex'), buf2.toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('copy in an interval', function (t) {
+ var rnd = crypto.randomBytes(10)
+ , b = BufferList(rnd) // put the random bytes there
+ , actual = new Buffer(3)
+ , expected = new Buffer(3)
+
+ rnd.copy(expected, 0, 5, 8)
+ b.copy(actual, 0, 5, 8)
+
+ t.equal(actual.toString('hex'), expected.toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('copy an interval between two buffers', function (t) {
+ var buf = crypto.randomBytes(10)
+ , buf2 = new Buffer(10)
+ , b = BufferList(buf)
+
+ b.append(buf)
+ b.copy(buf2, 0, 5, 15)
+
+ t.equal(b.slice(5, 15).toString('hex'), buf2.toString('hex'), 'same buffer')
+ t.end()
+})
+
+tape('duplicate', function (t) {
+ t.plan(2)
+
+ var bl = new BufferList('abcdefghij\xff\x00')
+ , dup = bl.duplicate()
+
+ t.equal(bl.prototype, dup.prototype)
+ t.equal(bl.toString('hex'), dup.toString('hex'))
+})
+
+tape('destroy no pipe', function (t) {
+ t.plan(2)
+
+ var bl = new BufferList('alsdkfja;lsdkfja;lsdk')
+ bl.destroy()
+
+ t.equal(bl._bufs.length, 0)
+ t.equal(bl.length, 0)
+})
+
+!process.browser && tape('destroy with pipe before read end', function (t) {
+ t.plan(2)
+
+ var bl = new BufferList()
+ fs.createReadStream(__dirname + '/sauce.js')
+ .pipe(bl)
+
+ bl.destroy()
+
+ t.equal(bl._bufs.length, 0)
+ t.equal(bl.length, 0)
+
+})
+
+!process.browser && tape('destroy with pipe before read end with race', function (t) {
+ t.plan(2)
+
+ var bl = new BufferList()
+ fs.createReadStream(__dirname + '/sauce.js')
+ .pipe(bl)
+
+ setTimeout(function () {
+ bl.destroy()
+ setTimeout(function () {
+ t.equal(bl._bufs.length, 0)
+ t.equal(bl.length, 0)
+ }, 500)
+ }, 500)
+})
+
+!process.browser && tape('destroy with pipe after read end', function (t) {
+ t.plan(2)
+
+ var bl = new BufferList()
+ fs.createReadStream(__dirname + '/sauce.js')
+ .on('end', onEnd)
+ .pipe(bl)
+
+ function onEnd () {
+ bl.destroy()
+
+ t.equal(bl._bufs.length, 0)
+ t.equal(bl.length, 0)
+ }
+})
+
+!process.browser && tape('destroy with pipe while writing to a destination', function (t) {
+ t.plan(4)
+
+ var bl = new BufferList()
+ , ds = new BufferList()
+
+ fs.createReadStream(__dirname + '/sauce.js')
+ .on('end', onEnd)
+ .pipe(bl)
+
+ function onEnd () {
+ bl.pipe(ds)
+
+ setTimeout(function () {
+ bl.destroy()
+
+ t.equals(bl._bufs.length, 0)
+ t.equals(bl.length, 0)
+
+ ds.destroy()
+
+ t.equals(bl._bufs.length, 0)
+ t.equals(bl.length, 0)
+
+ }, 100)
+ }
+})
+
+!process.browser && tape('handle error', function (t) {
+ t.plan(2)
+ fs.createReadStream('/does/not/exist').pipe(BufferList(function (err, data) {
+ t.ok(err instanceof Error, 'has error')
+ t.notOk(data, 'no data')
+ }))
+})
diff --git a/node_modules/request/node_modules/bl/test/sauce.js b/node_modules/request/node_modules/bl/test/sauce.js
new file mode 100644
index 000000000..a6d28625f
--- /dev/null
+++ b/node_modules/request/node_modules/bl/test/sauce.js
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+const user = process.env.SAUCE_USER
+ , key = process.env.SAUCE_KEY
+ , path = require('path')
+ , brtapsauce = require('brtapsauce')
+ , testFile = path.join(__dirname, 'basic-test.js')
+
+ , capabilities = [
+ { browserName: 'chrome' , platform: 'Windows XP', version: '' }
+ , { browserName: 'firefox' , platform: 'Windows 8' , version: '' }
+ , { browserName: 'firefox' , platform: 'Windows XP', version: '4' }
+ , { browserName: 'internet explorer' , platform: 'Windows 8' , version: '10' }
+ , { browserName: 'internet explorer' , platform: 'Windows 7' , version: '9' }
+ , { browserName: 'internet explorer' , platform: 'Windows 7' , version: '8' }
+ , { browserName: 'internet explorer' , platform: 'Windows XP', version: '7' }
+ , { browserName: 'internet explorer' , platform: 'Windows XP', version: '6' }
+ , { browserName: 'safari' , platform: 'Windows 7' , version: '5' }
+ , { browserName: 'safari' , platform: 'OS X 10.8' , version: '6' }
+ , { browserName: 'opera' , platform: 'Windows 7' , version: '' }
+ , { browserName: 'opera' , platform: 'Windows 7' , version: '11' }
+ , { browserName: 'ipad' , platform: 'OS X 10.8' , version: '6' }
+ , { browserName: 'android' , platform: 'Linux' , version: '4.0', 'device-type': 'tablet' }
+ ]
+
+if (!user)
+ throw new Error('Must set a SAUCE_USER env var')
+if (!key)
+ throw new Error('Must set a SAUCE_KEY env var')
+
+brtapsauce({
+ name : 'Traversty'
+ , user : user
+ , key : key
+ , brsrc : testFile
+ , capabilities : capabilities
+ , options : { timeout: 60 * 6 }
+}) \ No newline at end of file
diff --git a/node_modules/request/node_modules/bl/test/test.js b/node_modules/request/node_modules/bl/test/test.js
new file mode 100644
index 000000000..aa9b48771
--- /dev/null
+++ b/node_modules/request/node_modules/bl/test/test.js
@@ -0,0 +1,9 @@
+require('./basic-test')
+
+if (!process.env.SAUCE_KEY || !process.env.SAUCE_USER)
+ return console.log('SAUCE_KEY and/or SAUCE_USER not set, not running sauce tests')
+
+if (!/v0\.10/.test(process.version))
+ return console.log('Not Node v0.10.x, not running sauce tests')
+
+require('./sauce.js') \ No newline at end of file
diff --git a/node_modules/request/node_modules/caseless/LICENSE b/node_modules/request/node_modules/caseless/LICENSE
new file mode 100644
index 000000000..61789f4a4
--- /dev/null
+++ b/node_modules/request/node_modules/caseless/LICENSE
@@ -0,0 +1,28 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+1. Definitions.
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/node_modules/request/node_modules/caseless/README.md b/node_modules/request/node_modules/caseless/README.md
new file mode 100644
index 000000000..e5077a216
--- /dev/null
+++ b/node_modules/request/node_modules/caseless/README.md
@@ -0,0 +1,45 @@
+## Caseless -- wrap an object to set and get property with caseless semantics but also preserve caseing.
+
+This library is incredibly useful when working with HTTP headers. It allows you to get/set/check for headers in a caseless manner while also preserving the caseing of headers the first time they are set.
+
+## Usage
+
+```javascript
+var headers = {}
+ , c = caseless(headers)
+ ;
+c.set('a-Header', 'asdf')
+c.get('a-header') === 'asdf'
+```
+
+## has(key)
+
+Has takes a name and if it finds a matching header will return that header name with the preserved caseing it was set with.
+
+```javascript
+c.has('a-header') === 'a-Header'
+```
+
+## set(key, value[, clobber=true])
+
+Set is fairly straight forward except that if the header exists and clobber is disabled it will add `','+value` to the existing header.
+
+```javascript
+c.set('a-Header', 'fdas')
+c.set('a-HEADER', 'more', false)
+c.get('a-header') === 'fdsa,more'
+```
+
+## swap(key)
+
+Swaps the casing of a header with the new one that is passed in.
+
+```javascript
+var headers = {}
+ , c = caseless(headers)
+ ;
+c.set('a-Header', 'fdas')
+c.swap('a-HEADER')
+c.has('a-header') === 'a-HEADER'
+headers === {'a-HEADER': 'fdas'}
+```
diff --git a/node_modules/request/node_modules/caseless/index.js b/node_modules/request/node_modules/caseless/index.js
new file mode 100644
index 000000000..d86a70eca
--- /dev/null
+++ b/node_modules/request/node_modules/caseless/index.js
@@ -0,0 +1,66 @@
+function Caseless (dict) {
+ this.dict = dict || {}
+}
+Caseless.prototype.set = function (name, value, clobber) {
+ if (typeof name === 'object') {
+ for (var i in name) {
+ this.set(i, name[i], value)
+ }
+ } else {
+ if (typeof clobber === 'undefined') clobber = true
+ var has = this.has(name)
+
+ if (!clobber && has) this.dict[has] = this.dict[has] + ',' + value
+ else this.dict[has || name] = value
+ return has
+ }
+}
+Caseless.prototype.has = function (name) {
+ var keys = Object.keys(this.dict)
+ , name = name.toLowerCase()
+ ;
+ for (var i=0;i<keys.length;i++) {
+ if (keys[i].toLowerCase() === name) return keys[i]
+ }
+ return false
+}
+Caseless.prototype.get = function (name) {
+ name = name.toLowerCase()
+ var result, _key
+ var headers = this.dict
+ Object.keys(headers).forEach(function (key) {
+ _key = key.toLowerCase()
+ if (name === _key) result = headers[key]
+ })
+ return result
+}
+Caseless.prototype.swap = function (name) {
+ var has = this.has(name)
+ if (!has) throw new Error('There is no header than matches "'+name+'"')
+ this.dict[name] = this.dict[has]
+ delete this.dict[has]
+}
+Caseless.prototype.del = function (name) {
+ var has = this.has(name)
+ return delete this.dict[has || name]
+}
+
+module.exports = function (dict) {return new Caseless(dict)}
+module.exports.httpify = function (resp, headers) {
+ var c = new Caseless(headers)
+ resp.setHeader = function (key, value, clobber) {
+ if (typeof value === 'undefined') return
+ return c.set(key, value, clobber)
+ }
+ resp.hasHeader = function (key) {
+ return c.has(key)
+ }
+ resp.getHeader = function (key) {
+ return c.get(key)
+ }
+ resp.removeHeader = function (key) {
+ return c.del(key)
+ }
+ resp.headers = c.dict
+ return c
+}
diff --git a/node_modules/request/node_modules/caseless/package.json b/node_modules/request/node_modules/caseless/package.json
new file mode 100644
index 000000000..e0bd2851d
--- /dev/null
+++ b/node_modules/request/node_modules/caseless/package.json
@@ -0,0 +1,86 @@
+{
+ "_args": [
+ [
+ "caseless@~0.11.0",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "caseless@>=0.11.0 <0.12.0",
+ "_id": "caseless@0.11.0",
+ "_inCache": true,
+ "_location": "/request/caseless",
+ "_nodeVersion": "1.8.1",
+ "_npmUser": {
+ "email": "mikeal.rogers@gmail.com",
+ "name": "mikeal"
+ },
+ "_npmVersion": "2.8.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "caseless",
+ "raw": "caseless@~0.11.0",
+ "rawSpec": "~0.11.0",
+ "scope": null,
+ "spec": ">=0.11.0 <0.12.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
+ "_shasum": "715b96ea9841593cc33067923f5ec60ebda4f7d7",
+ "_shrinkwrap": null,
+ "_spec": "caseless@~0.11.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "author": {
+ "email": "mikeal.rogers@gmail.com",
+ "name": "Mikeal Rogers"
+ },
+ "bugs": {
+ "url": "https://github.com/mikeal/caseless/issues"
+ },
+ "dependencies": {},
+ "description": "Caseless object set/get/has, very useful when working with HTTP headers.",
+ "devDependencies": {
+ "tape": "^2.10.2"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "715b96ea9841593cc33067923f5ec60ebda4f7d7",
+ "tarball": "http://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+ },
+ "gitHead": "c578232a02cc2b46b6da8851caf57fdbfac89ff5",
+ "homepage": "https://github.com/mikeal/caseless#readme",
+ "keywords": [
+ "caseless",
+ "headers",
+ "http"
+ ],
+ "license": "Apache-2.0",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "mikeal",
+ "email": "mikeal.rogers@gmail.com"
+ },
+ {
+ "name": "nylen",
+ "email": "jnylen@gmail.com"
+ },
+ {
+ "name": "simov",
+ "email": "simeonvelichkov@gmail.com"
+ }
+ ],
+ "name": "caseless",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/mikeal/caseless.git"
+ },
+ "scripts": {
+ "test": "node test.js"
+ },
+ "test": "node test.js",
+ "version": "0.11.0"
+}
diff --git a/node_modules/request/node_modules/caseless/test.js b/node_modules/request/node_modules/caseless/test.js
new file mode 100644
index 000000000..084bbaf5e
--- /dev/null
+++ b/node_modules/request/node_modules/caseless/test.js
@@ -0,0 +1,40 @@
+var tape = require('tape')
+ , caseless = require('./')
+ ;
+
+tape('set get has', function (t) {
+ var headers = {}
+ , c = caseless(headers)
+ ;
+ t.plan(17)
+ c.set('a-Header', 'asdf')
+ t.equal(c.get('a-header'), 'asdf')
+ t.equal(c.has('a-header'), 'a-Header')
+ t.ok(!c.has('nothing'))
+ // old bug where we used the wrong regex
+ t.ok(!c.has('a-hea'))
+ c.set('a-header', 'fdsa')
+ t.equal(c.get('a-header'), 'fdsa')
+ t.equal(c.get('a-Header'), 'fdsa')
+ c.set('a-HEADER', 'more', false)
+ t.equal(c.get('a-header'), 'fdsa,more')
+
+ t.deepEqual(headers, {'a-Header': 'fdsa,more'})
+ c.swap('a-HEADER')
+ t.deepEqual(headers, {'a-HEADER': 'fdsa,more'})
+
+ c.set('deleteme', 'foobar')
+ t.ok(c.has('deleteme'))
+ t.ok(c.del('deleteme'))
+ t.notOk(c.has('deleteme'))
+ t.notOk(c.has('idonotexist'))
+ t.ok(c.del('idonotexist'))
+
+ c.set('tva', 'test1')
+ c.set('tva-header', 'test2')
+ t.equal(c.has('tva'), 'tva')
+ t.notOk(c.has('header'))
+
+ t.equal(c.get('tva'), 'test1')
+
+})
diff --git a/node_modules/request/node_modules/extend/.jscs.json b/node_modules/request/node_modules/extend/.jscs.json
new file mode 100644
index 000000000..7e84b282b
--- /dev/null
+++ b/node_modules/request/node_modules/extend/.jscs.json
@@ -0,0 +1,104 @@
+{
+ "additionalRules": [],
+
+ "requireSemicolons": true,
+
+ "disallowMultipleSpaces": true,
+
+ "disallowIdentifierNames": [],
+
+ "requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
+
+ "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch", "function"],
+
+ "disallowSpaceAfterKeywords": [],
+
+ "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true },
+ "requireSpacesInNamedFunctionExpression": { "beforeOpeningCurlyBrace": true },
+ "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true },
+ "requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true },
+ "disallowSpacesInFunctionDeclaration": { "beforeOpeningRoundBrace": true },
+
+ "requireSpaceBetweenArguments": true,
+
+ "disallowSpacesInsideParentheses": true,
+
+ "disallowSpacesInsideArrayBrackets": true,
+
+ "disallowQuotedKeysInObjects": "allButReserved",
+
+ "disallowSpaceAfterObjectKeys": true,
+
+ "requireCommaBeforeLineBreak": true,
+
+ "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
+ "requireSpaceAfterPrefixUnaryOperators": [],
+
+ "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
+ "requireSpaceBeforePostfixUnaryOperators": [],
+
+ "disallowSpaceBeforeBinaryOperators": [],
+ "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
+
+ "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
+ "disallowSpaceAfterBinaryOperators": [],
+
+ "disallowImplicitTypeConversion": ["binary", "string"],
+
+ "disallowKeywords": ["with", "eval"],
+
+ "requireKeywordsOnNewLine": [],
+ "disallowKeywordsOnNewLine": ["else"],
+
+ "requireLineFeedAtFileEnd": true,
+
+ "disallowTrailingWhitespace": true,
+
+ "disallowTrailingComma": true,
+
+ "excludeFiles": ["node_modules/**", "vendor/**"],
+
+ "disallowMultipleLineStrings": true,
+
+ "requireDotNotation": true,
+
+ "requireParenthesesAroundIIFE": true,
+
+ "validateLineBreaks": "LF",
+
+ "validateQuoteMarks": {
+ "escape": true,
+ "mark": "'"
+ },
+
+ "disallowOperatorBeforeLineBreak": [],
+
+ "requireSpaceBeforeKeywords": [
+ "do",
+ "for",
+ "if",
+ "else",
+ "switch",
+ "case",
+ "try",
+ "catch",
+ "finally",
+ "while",
+ "with",
+ "return"
+ ],
+
+ "validateAlignedFunctionParameters": {
+ "lineBreakAfterOpeningBraces": true,
+ "lineBreakBeforeClosingBraces": true
+ },
+
+ "requirePaddingNewLinesBeforeExport": true,
+
+ "validateNewlineAfterArrayElements": {
+ "maximum": 6
+ },
+
+ "requirePaddingNewLinesAfterUseStrict": true
+}
+
diff --git a/node_modules/request/node_modules/extend/.npmignore b/node_modules/request/node_modules/extend/.npmignore
new file mode 100644
index 000000000..30d74d258
--- /dev/null
+++ b/node_modules/request/node_modules/extend/.npmignore
@@ -0,0 +1 @@
+test \ No newline at end of file
diff --git a/node_modules/request/node_modules/extend/.travis.yml b/node_modules/request/node_modules/extend/.travis.yml
new file mode 100644
index 000000000..ebef64499
--- /dev/null
+++ b/node_modules/request/node_modules/extend/.travis.yml
@@ -0,0 +1,44 @@
+language: node_js
+node_js:
+ - "iojs-v2.3"
+ - "iojs-v2.2"
+ - "iojs-v2.1"
+ - "iojs-v2.0"
+ - "iojs-v1.8"
+ - "iojs-v1.7"
+ - "iojs-v1.6"
+ - "iojs-v1.5"
+ - "iojs-v1.4"
+ - "iojs-v1.3"
+ - "iojs-v1.2"
+ - "iojs-v1.1"
+ - "iojs-v1.0"
+ - "0.12"
+ - "0.11"
+ - "0.10"
+ - "0.9"
+ - "0.8"
+ - "0.6"
+ - "0.4"
+before_install:
+ - '[ "${TRAVIS_NODE_VERSION}" = "0.6" ] || npm install -g npm@1.4.28 && npm install -g npm'
+sudo: false
+matrix:
+ fast_finish: true
+ allow_failures:
+ - node_js: "iojs-v2.2"
+ - node_js: "iojs-v2.1"
+ - node_js: "iojs-v2.0"
+ - node_js: "iojs-v1.7"
+ - node_js: "iojs-v1.6"
+ - node_js: "iojs-v1.5"
+ - node_js: "iojs-v1.4"
+ - node_js: "iojs-v1.3"
+ - node_js: "iojs-v1.2"
+ - node_js: "iojs-v1.1"
+ - node_js: "iojs-v1.0"
+ - node_js: "0.11"
+ - node_js: "0.9"
+ - node_js: "0.8"
+ - node_js: "0.6"
+ - node_js: "0.4"
diff --git a/node_modules/request/node_modules/extend/CHANGELOG.md b/node_modules/request/node_modules/extend/CHANGELOG.md
new file mode 100644
index 000000000..ee0cfd6ad
--- /dev/null
+++ b/node_modules/request/node_modules/extend/CHANGELOG.md
@@ -0,0 +1,69 @@
+3.0.0 / 2015-07-01
+==================
+ * [Possible breaking change] Use global "strict" directive (#32)
+ * [Tests] `int` is an ES3 reserved word
+ * [Tests] Test up to `io.js` `v2.3`
+ * [Tests] Add `npm run eslint`
+ * [Dev Deps] Update `covert`, `jscs`
+
+2.0.1 / 2015-04-25
+==================
+ * Use an inline `isArray` check, for ES3 browsers. (#27)
+ * Some old browsers fail when an identifier is `toString`
+ * Test latest `node` and `io.js` versions on `travis-ci`; speed up builds
+ * Add license info to package.json (#25)
+ * Update `tape`, `jscs`
+ * Adding a CHANGELOG
+
+2.0.0 / 2014-10-01
+==================
+ * Increase code coverage to 100%; run code coverage as part of tests
+ * Add `npm run lint`; Run linter as part of tests
+ * Remove nodeType and setInterval checks in isPlainObject
+ * Updating `tape`, `jscs`, `covert`
+ * General style and README cleanup
+
+1.3.0 / 2014-06-20
+==================
+ * Add component.json for browser support (#18)
+ * Use SVG for badges in README (#16)
+ * Updating `tape`, `covert`
+ * Updating travis-ci to work with multiple node versions
+ * Fix `deep === false` bug (returning target as {}) (#14)
+ * Fixing constructor checks in isPlainObject
+ * Adding additional test coverage
+ * Adding `npm run coverage`
+ * Add LICENSE (#13)
+ * Adding a warning about `false`, per #11
+ * General style and whitespace cleanup
+
+1.2.1 / 2013-09-14
+==================
+ * Fixing hasOwnProperty bugs that would only have shown up in specific browsers. Fixes #8
+ * Updating `tape`
+
+1.2.0 / 2013-09-02
+==================
+ * Updating the README: add badges
+ * Adding a missing variable reference.
+ * Using `tape` instead of `buster` for tests; add more tests (#7)
+ * Adding node 0.10 to Travis CI (#6)
+ * Enabling "npm test" and cleaning up package.json (#5)
+ * Add Travis CI.
+
+1.1.3 / 2012-12-06
+==================
+ * Added unit tests.
+ * Ensure extend function is named. (Looks nicer in a stack trace.)
+ * README cleanup.
+
+1.1.1 / 2012-11-07
+==================
+ * README cleanup.
+ * Added installation instructions.
+ * Added a missing semicolon
+
+1.0.0 / 2012-04-08
+==================
+ * Initial commit
+
diff --git a/node_modules/request/node_modules/extend/LICENSE b/node_modules/request/node_modules/extend/LICENSE
new file mode 100644
index 000000000..e16d6a56c
--- /dev/null
+++ b/node_modules/request/node_modules/extend/LICENSE
@@ -0,0 +1,23 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Stefan Thomas
+
+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.
+
diff --git a/node_modules/request/node_modules/extend/README.md b/node_modules/request/node_modules/extend/README.md
new file mode 100644
index 000000000..632fb0f96
--- /dev/null
+++ b/node_modules/request/node_modules/extend/README.md
@@ -0,0 +1,62 @@
+[![Build Status][travis-svg]][travis-url]
+[![dependency status][deps-svg]][deps-url]
+[![dev dependency status][dev-deps-svg]][dev-deps-url]
+
+# extend() for Node.js <sup>[![Version Badge][npm-version-png]][npm-url]</sup>
+
+`node-extend` is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true.
+
+## Installation
+
+This package is available on [npm][npm-url] as: `extend`
+
+``` sh
+npm install extend
+```
+
+## Usage
+
+**Syntax:** extend **(** [`deep`], `target`, `object1`, [`objectN`] **)**
+
+*Extend one object with one or more others, returning the modified object.*
+
+Keep in mind that the target object will be modified, and will be returned from extend().
+
+If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s).
+Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over.
+Warning: passing `false` as the first argument is not supported.
+
+### Arguments
+
+* `deep` *Boolean* (optional)
+If set, the merge becomes recursive (i.e. deep copy).
+* `target` *Object*
+The object to extend.
+* `object1` *Object*
+The object that will be merged into the first.
+* `objectN` *Object* (Optional)
+More objects to merge into the first.
+
+## License
+
+`node-extend` is licensed under the [MIT License][mit-license-url].
+
+## Acknowledgements
+
+All credit to the jQuery authors for perfecting this amazing utility.
+
+Ported to Node.js by [Stefan Thomas][github-justmoon] with contributions by [Jonathan Buchanan][github-insin] and [Jordan Harband][github-ljharb].
+
+[travis-svg]: https://travis-ci.org/justmoon/node-extend.svg
+[travis-url]: https://travis-ci.org/justmoon/node-extend
+[npm-url]: https://npmjs.org/package/extend
+[mit-license-url]: http://opensource.org/licenses/MIT
+[github-justmoon]: https://github.com/justmoon
+[github-insin]: https://github.com/insin
+[github-ljharb]: https://github.com/ljharb
+[npm-version-png]: http://vb.teelaun.ch/justmoon/node-extend.svg
+[deps-svg]: https://david-dm.org/justmoon/node-extend.svg
+[deps-url]: https://david-dm.org/justmoon/node-extend
+[dev-deps-svg]: https://david-dm.org/justmoon/node-extend/dev-status.svg
+[dev-deps-url]: https://david-dm.org/justmoon/node-extend#info=devDependencies
+
diff --git a/node_modules/request/node_modules/extend/component.json b/node_modules/request/node_modules/extend/component.json
new file mode 100644
index 000000000..1500a2f37
--- /dev/null
+++ b/node_modules/request/node_modules/extend/component.json
@@ -0,0 +1,32 @@
+{
+ "name": "extend",
+ "author": "Stefan Thomas <justmoon@members.fsf.org> (http://www.justmoon.net)",
+ "version": "3.0.0",
+ "description": "Port of jQuery.extend for node.js and the browser.",
+ "scripts": [
+ "index.js"
+ ],
+ "contributors": [
+ {
+ "name": "Jordan Harband",
+ "url": "https://github.com/ljharb"
+ }
+ ],
+ "keywords": [
+ "extend",
+ "clone",
+ "merge"
+ ],
+ "repository" : {
+ "type": "git",
+ "url": "https://github.com/justmoon/node-extend.git"
+ },
+ "dependencies": {
+ },
+ "devDependencies": {
+ "tape" : "~3.0.0",
+ "covert": "~0.4.0",
+ "jscs": "~1.6.2"
+ }
+}
+
diff --git a/node_modules/request/node_modules/extend/index.js b/node_modules/request/node_modules/extend/index.js
new file mode 100644
index 000000000..f5ec75d52
--- /dev/null
+++ b/node_modules/request/node_modules/extend/index.js
@@ -0,0 +1,86 @@
+'use strict';
+
+var hasOwn = Object.prototype.hasOwnProperty;
+var toStr = Object.prototype.toString;
+
+var isArray = function isArray(arr) {
+ if (typeof Array.isArray === 'function') {
+ return Array.isArray(arr);
+ }
+
+ return toStr.call(arr) === '[object Array]';
+};
+
+var isPlainObject = function isPlainObject(obj) {
+ if (!obj || toStr.call(obj) !== '[object Object]') {
+ return false;
+ }
+
+ var hasOwnConstructor = hasOwn.call(obj, 'constructor');
+ var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
+ // Not own constructor property must be Object
+ if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ var key;
+ for (key in obj) {/**/}
+
+ return typeof key === 'undefined' || hasOwn.call(obj, key);
+};
+
+module.exports = function extend() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0],
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if (typeof target === 'boolean') {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
+ target = {};
+ }
+
+ for (; i < length; ++i) {
+ options = arguments[i];
+ // Only deal with non-null/undefined values
+ if (options != null) {
+ // Extend the base object
+ for (name in options) {
+ src = target[name];
+ copy = options[name];
+
+ // Prevent never-ending loop
+ if (target !== copy) {
+ // Recurse if we're merging plain objects or arrays
+ if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
+ if (copyIsArray) {
+ copyIsArray = false;
+ clone = src && isArray(src) ? src : [];
+ } else {
+ clone = src && isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[name] = extend(deep, clone, copy);
+
+ // Don't bring in undefined values
+ } else if (typeof copy !== 'undefined') {
+ target[name] = copy;
+ }
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
diff --git a/node_modules/request/node_modules/extend/package.json b/node_modules/request/node_modules/extend/package.json
new file mode 100644
index 000000000..a8d452ca1
--- /dev/null
+++ b/node_modules/request/node_modules/extend/package.json
@@ -0,0 +1,96 @@
+{
+ "_args": [
+ [
+ "extend@~3.0.0",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "extend@>=3.0.0 <3.1.0",
+ "_id": "extend@3.0.0",
+ "_inCache": true,
+ "_location": "/request/extend",
+ "_nodeVersion": "2.3.1",
+ "_npmUser": {
+ "email": "ljharb@gmail.com",
+ "name": "ljharb"
+ },
+ "_npmVersion": "2.11.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "extend",
+ "raw": "extend@~3.0.0",
+ "rawSpec": "~3.0.0",
+ "scope": null,
+ "spec": ">=3.0.0 <3.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
+ "_shasum": "5a474353b9f3353ddd8176dfd37b91c83a46f1d4",
+ "_shrinkwrap": null,
+ "_spec": "extend@~3.0.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "author": {
+ "email": "justmoon@members.fsf.org",
+ "name": "Stefan Thomas",
+ "url": "http://www.justmoon.net"
+ },
+ "bugs": {
+ "url": "https://github.com/justmoon/node-extend/issues"
+ },
+ "contributors": [
+ {
+ "name": "Jordan Harband",
+ "url": "https://github.com/ljharb"
+ }
+ ],
+ "dependencies": {},
+ "description": "Port of jQuery.extend for node.js and the browser",
+ "devDependencies": {
+ "covert": "^1.1.0",
+ "eslint": "^0.24.0",
+ "jscs": "^1.13.1",
+ "tape": "^4.0.0"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "5a474353b9f3353ddd8176dfd37b91c83a46f1d4",
+ "tarball": "http://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+ },
+ "gitHead": "148e7270cab2e9413af2cd0cab147070d755ed6d",
+ "homepage": "https://github.com/justmoon/node-extend#readme",
+ "keywords": [
+ "clone",
+ "extend",
+ "merge"
+ ],
+ "license": "MIT",
+ "main": "index",
+ "maintainers": [
+ {
+ "name": "justmoon",
+ "email": "justmoon@members.fsf.org"
+ },
+ {
+ "name": "ljharb",
+ "email": "ljharb@gmail.com"
+ }
+ ],
+ "name": "extend",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/justmoon/node-extend.git"
+ },
+ "scripts": {
+ "coverage": "covert test/index.js",
+ "coverage-quiet": "covert test/index.js --quiet",
+ "eslint": "eslint *.js */*.js",
+ "jscs": "jscs *.js */*.js",
+ "lint": "npm run jscs && npm run eslint",
+ "test": "npm run lint && node test/index.js && npm run coverage-quiet"
+ },
+ "version": "3.0.0"
+}
diff --git a/node_modules/request/node_modules/hawk/.npmignore b/node_modules/request/node_modules/hawk/.npmignore
new file mode 100644
index 000000000..96ed0910b
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/.npmignore
@@ -0,0 +1,20 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+components
+build
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+
diff --git a/node_modules/request/node_modules/hawk/.travis.yml b/node_modules/request/node_modules/hawk/.travis.yml
new file mode 100755
index 000000000..40ca59eee
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+ - 0.10
+
diff --git a/node_modules/request/node_modules/hawk/LICENSE b/node_modules/request/node_modules/hawk/LICENSE
new file mode 100755
index 000000000..788093684
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012-2014, Eran Hammer 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/hueniverse/hawk/graphs/contributors
diff --git a/node_modules/request/node_modules/hawk/README.md b/node_modules/request/node_modules/hawk/README.md
new file mode 100755
index 000000000..4aff23f3a
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/README.md
@@ -0,0 +1,634 @@
+![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)
+
+<img align="right" src="https://raw.github.com/hueniverse/hawk/master/images/logo.png" /> **Hawk** is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial
+HTTP request cryptographic verification. For more complex use cases such as access delegation, see [Oz](https://github.com/hueniverse/oz).
+
+Current version: **3.x**
+
+Note: 3.x and 2.x are the same exact protocol as 1.1. The version increments reflect changes in the node API.
+
+[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)
+
+# Table of Content
+
+- [**Introduction**](#introduction)
+ - [Replay Protection](#replay-protection)
+ - [Usage Example](#usage-example)
+ - [Protocol Example](#protocol-example)
+ - [Payload Validation](#payload-validation)
+ - [Response Payload Validation](#response-payload-validation)
+ - [Browser Support and Considerations](#browser-support-and-considerations)
+<p></p>
+- [**Single URI Authorization**](#single-uri-authorization)
+ - [Usage Example](#bewit-usage-example)
+<p></p>
+- [**Security Considerations**](#security-considerations)
+ - [MAC Keys Transmission](#mac-keys-transmission)
+ - [Confidentiality of Requests](#confidentiality-of-requests)
+ - [Spoofing by Counterfeit Servers](#spoofing-by-counterfeit-servers)
+ - [Plaintext Storage of Credentials](#plaintext-storage-of-credentials)
+ - [Entropy of Keys](#entropy-of-keys)
+ - [Coverage Limitations](#coverage-limitations)
+ - [Future Time Manipulation](#future-time-manipulation)
+ - [Client Clock Poisoning](#client-clock-poisoning)
+ - [Bewit Limitations](#bewit-limitations)
+ - [Host Header Forgery](#host-header-forgery)
+<p></p>
+- [**Frequently Asked Questions**](#frequently-asked-questions)
+<p></p>
+- [**Implementations**](#implementations)
+- [**Acknowledgements**](#acknowledgements)
+
+# Introduction
+
+**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with
+partial cryptographic verification of the request and response, covering the HTTP method, request URI, host,
+and optionally the request payload.
+
+Similar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of
+client credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme,
+the key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is
+included in its place.
+
+However, **Hawk** has several differences from Digest. In particular, while both use a nonce to limit the possibility of
+replay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less
+"chattiness" (interaction with the server).
+
+Also unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because
+the client and server must both have access to the key material in the clear.
+
+The primary design goals of this scheme are to:
+* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources,
+* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where
+ to send an authenticated request), and
+* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client
+ failure to validate the server's identity as part of its TLS handshake.
+
+In addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using
+a query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk).
+
+The **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server,
+which is beyond the scope of this module. Typically, the shared credentials are established via an initial
+TLS-protected phase or derived from some other shared confidential information available to both the client
+and the server.
+
+
+## Replay Protection
+
+Without replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more
+than once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when
+making requests. This gives the server enough information to prevent replay attacks.
+
+The nonce is generated by the client, and is a string unique across all requests with the same timestamp and
+key identifier combination.
+
+The timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards
+are rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.
+By default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in
+practice translates to a maximum of 2 minutes as the skew can be positive or negative).
+
+Using a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client
+clock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types
+(e.g. browsers) to deploy NTP, the server provides the client with its current time (in seconds precision) in response
+to a bad timestamp.
+
+There is no expectation that the client will adjust its system clock to match the server (in fact, this would be a
+potential attack vector). Instead, the client only uses the server's time to calculate an offset used only
+for communications with that particular server. The protocol rewards clients with synchronized clocks by reducing
+the number of round trips required to authenticate the first request.
+
+
+## Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'Steve'
+ };
+
+ return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+ // Authenticate incoming request
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ // Prepare response
+
+ var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
+ var headers = { 'Content-Type': 'text/plain' };
+
+ // Generate Server-Authorization response header
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: payload, contentType: headers['Content-Type'] });
+ headers['Server-Authorization'] = header;
+
+ // Send the response back
+
+ res.writeHead(!err ? 200 : 401, headers);
+ res.end(payload);
+ });
+};
+
+// Start server
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Client code:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+ id: 'dh37fgj492je',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+}
+
+// Request options
+
+var requestOptions = {
+ uri: 'http://example.com:8000/resource/1?b=1&a=2',
+ method: 'GET',
+ headers: {}
+};
+
+// Generate Authorization request header
+
+var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
+requestOptions.headers.Authorization = header.field;
+
+// Send authenticated request
+
+Request(requestOptions, function (error, response, body) {
+
+ // Authenticate the server's response
+
+ var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
+
+ // Output results
+
+ console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
+});
+```
+
+**Hawk** utilized the [**SNTP**](https://github.com/hueniverse/sntp) module for time sync management. By default, the local
+machine time is used. To automatically retrieve and synchronice the clock within the application, use the SNTP 'start()' method.
+
+```javascript
+Hawk.sntp.start();
+```
+
+
+## Protocol Example
+
+The client attempts to access a protected resource without authentication, sending the following HTTP request to
+the resource server:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+```
+
+The resource server returns an authentication challenge.
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Hawk
+```
+
+The client has previously obtained a set of **Hawk** credentials for accessing resources on the "http://example.com/"
+server. The **Hawk** credentials issued to the client include the following attributes:
+
+* Key identifier: dh37fgj492je
+* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn
+* Algorithm: sha256
+
+The client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1,
+1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline
+character):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+GET
+/resource/1?b=1&a=2
+example.com
+8000
+
+some-app-ext-data
+
+```
+
+The request MAC is calculated using HMAC with the specified hash algorithm "sha256" and the key over the normalized request string.
+The result is base64-encoded to produce the request MAC:
+
+```
+6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=
+```
+
+The client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using
+the HTTP `Authorization` request header field:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="
+```
+
+The server validates the request by calculating the request MAC again based on the request received and verifies the validity
+and scope of the **Hawk** credentials. If valid, the server responds with the requested resource.
+
+
+### Payload Validation
+
+**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash
+using the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character):
+* `hawk.1.payload`
+* the content-type in lowercase, without any parameters (e.g. `application/json`)
+* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)
+
+For example:
+
+* Payload: `Thank you for flying Hawk`
+* Content Type: `text/plain`
+* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`
+
+Results in the following input to the payload hash function (newline terminated values):
+
+```
+hawk.1.payload
+text/plain
+Thank you for flying Hawk
+
+```
+
+Which produces the following hash value:
+
+```
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+```
+
+The client constructs the normalized request string (newline terminated values):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+POST
+/resource/1?a=1&b=2
+example.com
+8000
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+some-app-ext-data
+
+```
+
+Then calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data,
+and request MAC, with the request using the HTTP `Authorization` request header field:
+
+```
+POST /resource/1?a=1&b=2 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="
+```
+
+It is up to the server if and when it validates the payload for any given request, based solely on it's security policy
+and the nature of the data included.
+
+If the payload is available at the time of authentication, the server uses the hash value provided by the client to construct
+the normalized string and validates the MAC. If the MAC is valid, the server calculates the payload hash and compares the value
+with the provided payload hash in the header. In many cases, checking the MAC first is faster than calculating the payload hash.
+
+However, if the payload is not available at authentication time (e.g. too large to fit in memory, streamed elsewhere, or processed
+at a different stage in the application), the server may choose to defer payload validation for later by retaining the hash value
+provided by the client after validating the MAC.
+
+It is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value
+included in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided
+by the client, the payload may be modified by an attacker.
+
+
+## Response Payload Validation
+
+**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the
+client to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header
+as a response header using the exact same syntax as the `Authorization` request header field.
+
+The header is contructed using the same process as the client's request header. The server uses the same credentials and other
+artifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with
+new values based on the server response. The rest as identical to those used by the client.
+
+The result MAC digest is included with the optional `hash` and `ext` values:
+
+```
+Server-Authorization: Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"
+```
+
+
+## Browser Support and Considerations
+
+A browser script is provided for including using a `<script>` tag in [lib/browser.js](/lib/browser.js). It's also a [component](http://component.io/hueniverse/hawk).
+
+**Hawk** relies on the _Server-Authorization_ and _WWW-Authenticate_ headers in its response to communicate with the client.
+Therefore, in case of CORS requests, it is important to consider sending _Access-Control-Expose-Headers_ with the value
+_"WWW-Authenticate, Server-Authorization"_ on each response from your server. As explained in the
+[specifications](http://www.w3.org/TR/cors/#access-control-expose-headers-response-header), it will indicate that these headers
+can safely be accessed by the client (using getResponseHeader() on the XmlHttpRequest object). Otherwise you will be met with a
+["simple response header"](http://www.w3.org/TR/cors/#simple-response-header) which excludes these fields and would prevent the
+Hawk client from authenticating the requests.You can read more about the why and how in this
+[article](http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server)
+
+
+# Single URI Authorization
+
+There are cases in which limited and short-term access to a protected resource is granted to a third party which does not
+have access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk**
+provides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains
+the necessary credentials to authenticate the request.
+
+Because of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests
+and for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same
+credentials as the client to maintain clear traceability as to who issued which credentials.
+
+In order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within
+the granted access timeframe.
+
+
+## Bewit Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+ };
+
+ return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
+ res.end(!err ? 'Access granted' : 'Shoosh!');
+ });
+};
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Bewit code generation:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+ id: 'dh37fgj492je',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+}
+
+// Generate bewit
+
+var duration = 60 * 5; // 5 Minutes
+var bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });
+var uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;
+```
+
+
+# Security Considerations
+
+The greatest sources of security risks are usually found not in **Hawk** but in the policies and procedures surrounding its use.
+Implementers are strongly encouraged to assess how this module addresses their security requirements. This section includes
+an incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server.
+Many of the protections provided in **Hawk** depends on whether and how they are used.
+
+### MAC Keys Transmission
+
+**Hawk** does not provide any mechanism for obtaining or transmitting the set of shared credentials required. Any mechanism used
+to obtain **Hawk** credentials must ensure that these transmissions are protected using transport-layer mechanisms such as TLS.
+
+### Confidentiality of Requests
+
+While **Hawk** provides a mechanism for verifying the integrity of HTTP requests, it provides no guarantee of request
+confidentiality. Unless other precautions are taken, eavesdroppers will have full access to the request content. Servers should
+carefully consider the types of data likely to be sent as part of such requests, and employ transport-layer security mechanisms
+to protect sensitive resources.
+
+### Spoofing by Counterfeit Servers
+
+**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server
+may choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to
+the server to determine when such measure is included, to up to the client to enforce that policy.
+
+A hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise
+incorrect responses. Service providers should consider such attacks when developing services using this protocol, and should
+require transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue.
+
+### Plaintext Storage of Credentials
+
+The **Hawk** key functions the same way passwords do in traditional authentication systems. In order to compute the request MAC,
+the server must have access to the key in plaintext form. This is in contrast, for example, to modern operating systems, which
+store only a one-way hash of user credentials.
+
+If an attacker were to gain access to these keys - or worse, to the server's database of all such keys - he or she would be able
+to perform any action on behalf of any resource owner. Accordingly, it is critical that servers protect these keys from unauthorized
+access.
+
+### Entropy of Keys
+
+Unless a transport-layer security protocol is used, eavesdroppers will have full access to authenticated requests and request
+MAC values, and will thus be able to mount offline brute-force attacks to recover the key used. Servers should be careful to
+assign keys which are long enough, and random enough, to resist such attacks for at least the length of time that the **Hawk**
+credentials are valid.
+
+For example, if the credentials are valid for two weeks, servers should ensure that it is not possible to mount a brute force
+attack that recovers the key in less than two weeks. Of course, servers are urged to err on the side of caution, and use the
+longest key reasonable.
+
+It is equally important that the pseudo-random number generator (PRNG) used to generate these keys be of sufficiently high
+quality. Many PRNG implementations generate number sequences that may appear to be random, but which nevertheless exhibit
+patterns or other weaknesses which make cryptanalysis or brute force attacks easier. Implementers should be careful to use
+cryptographically secure PRNGs to avoid these problems.
+
+### Coverage Limitations
+
+The request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers
+which can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence
+or value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the
+`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC.
+
+The response authentication, when performed, only covers the response payload, content-type, and the request information
+provided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or
+any other response header field (e.g. Location) which can affect the client's behaviour.
+
+### Future Time Manipulation
+
+The protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its
+current time when an invalid timestamp is received.
+
+If an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause
+the client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will
+not likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then
+be able to replay the request at the correct time without detection.
+
+The client must only use the time information provided by the server if:
+* it was delivered over a TLS connection and the server identity has been verified, or
+* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified.
+
+### Client Clock Poisoning
+
+When receiving a request with a bad timestamp, the server provides the client with its current time. The client must never use
+the time received from the server to adjust its own clock, and must only use it to calculate an offset for communicating with
+that particular server.
+
+### Bewit Limitations
+
+Special care must be taken when issuing bewit credentials to third parties. Bewit credentials are valid until expiration and cannot
+be revoked or limited without using other means. Whatever resource they grant access to will be completely exposed to anyone with
+access to the bewit credentials which act as bearer credentials for that particular resource. While bewit usage is limited to GET
+requests only and therefore cannot be used to perform transactions or change server state, it can still be used to expose private
+and sensitive information.
+
+### Host Header Forgery
+
+Hawk validates the incoming request MAC against the incoming HTTP Host header. However, unless the optional `host` and `port`
+options are used with `server.authenticate()`, a malicous client can mint new host names pointing to the server's IP address and
+use that to craft an attack by sending a valid request that's meant for another hostname than the one used by the server. Server
+implementors must manually verify that the host header received matches their expectation (or use the options mentioned above).
+
+# Frequently Asked Questions
+
+### Where is the protocol specification?
+
+If you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source
+project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about
+something? Open an issue!
+
+### Is it done?
+
+As of version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental
+and is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions
+and suggestions.
+
+### Where can I find **Hawk** implementations in other languages?
+
+**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, it has been ported to other languages.
+The full list is maintained [here](https://github.com/hueniverse/hawk/issues?labels=port&state=closed). Please add an issue if you are
+working on another port. A cross-platform test-suite is in the works.
+
+### Why isn't the algorithm part of the challenge or dynamically negotiated?
+
+The algorithm used is closely related to the key issued as different algorithms require different key sizes (and other
+requirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm
+together as part of the issued credentials.
+
+### Why is Host and Content-Type the only headers covered by the request MAC?
+
+It is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no
+well-established way to normalize them. Many platforms change the case of header field names and values. The only
+straight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request,
+an approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information,
+and introduces other security issues because firewalls will not be aware of these "hidden" headers. In addition, any information
+repeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere.
+
+### Why not just use HTTP Digest?
+
+Digest requires pre-negotiation to establish a nonce. This means you can't just make a request - you must first send
+a protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile
+where extra round-trip are costly.
+
+### Why bother with all this nonce and timestamp business?
+
+**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp
+and nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses
+it by requiring the client to sync its clock, but provides it with tools to accomplish it.
+
+In general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected
+system where the clients are implemented using best practices and are under the control of the server. Instead of dropping
+replay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers
+with the ability to decide how to enforce their security policy without impacting the client's implementation.
+
+### What are `app` and `dlg` in the authorization header and normalized mac string?
+
+The original motivation for **Hawk** was to replace the OAuth 1.0 use cases. This included both a simple client-server mode which
+this module is specifically designed for, and a delegated access mode which is being developed separately in
+[Oz](https://github.com/hueniverse/oz). In addition to the **Hawk** use cases, Oz requires another attribute: the application id `app`.
+This provides binding between the credentials and the application in a way that prevents an attacker from tricking an application
+to use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the
+application the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly,
+but with the additional security of delegated credentials.
+
+### What is the purpose of the static strings used in each normalized MAC input?
+
+When calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being
+used or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request,
+response, and a bewit use cases). It also protects against exploits created after a potential change in how the protocol
+creates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it
+can create an exploit opportunity for cases where the nonce is similar in format to a timestamp.
+
+### Does **Hawk** have anything to do with OAuth?
+
+Short answer: no.
+
+**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent
+incompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it
+to authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard
+at work to produce more garbage.
+
+**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case
+of delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](https://github.com/hueniverse/oz).
+
+# Implementations
+
+- [Logibit Hawk in F#/.Net](https://github.com/logibit/logibit.hawk/)
+- [Tent Hawk in Ruby](https://github.com/tent/hawk-ruby)
+- [Wealdtech in Java](https://github.com/wealdtech/hawk)
+- [Kumar's Mohawk in Python](https://github.com/kumar303/mohawk/)
+
+# Acknowledgements
+
+**Hawk** is a derivative work of the [HTTP MAC Authentication Scheme](http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) proposal
+co-authored by Ben Adida, Adam Barth, and Eran Hammer, which in turn was based on the OAuth 1.0 community specification.
+
+Special thanks to Ben Laurie for his always insightful feedback and advice.
+
+The **Hawk** logo was created by [Chris Carrasco](http://chriscarrasco.com).
diff --git a/node_modules/request/node_modules/hawk/bower.json b/node_modules/request/node_modules/hawk/bower.json
new file mode 100644
index 000000000..7d2d120e0
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/bower.json
@@ -0,0 +1,24 @@
+{
+ "name": "hawk",
+ "main": "lib/browser.js",
+ "license": "./LICENSE",
+ "ignore": [
+ "!lib",
+ "lib/*",
+ "!lib/browser.js",
+ "index.js"
+ ],
+ "keywords": [
+ "http",
+ "authentication",
+ "scheme",
+ "hawk"
+ ],
+ "authors": [
+ "Eran Hammer <eran@hammer.io>"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/hueniverse/hawk.git"
+ }
+}
diff --git a/node_modules/request/node_modules/hawk/component.json b/node_modules/request/node_modules/hawk/component.json
new file mode 100644
index 000000000..63e76a2e3
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/component.json
@@ -0,0 +1,19 @@
+{
+ "name": "hawk",
+ "repo": "hueniverse/hawk",
+ "description": "HTTP Hawk Authentication Scheme",
+ "version": "1.0.0",
+ "keywords": [
+ "http",
+ "authentication",
+ "scheme",
+ "hawk"
+ ],
+ "dependencies": {},
+ "development": {},
+ "license": "BSD",
+ "main": "lib/browser.js",
+ "scripts": [
+ "lib/browser.js"
+ ]
+} \ No newline at end of file
diff --git a/node_modules/request/node_modules/hawk/example/usage.js b/node_modules/request/node_modules/hawk/example/usage.js
new file mode 100755
index 000000000..13b860b4c
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/example/usage.js
@@ -0,0 +1,78 @@
+// Load modules
+
+var Http = require('http');
+var Request = require('request');
+var Hawk = require('../lib');
+
+
+// Declare internals
+
+var internals = {
+ credentials: {
+ dh37fgj492je: {
+ id: 'dh37fgj492je', // Required by Hawk.client.header
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'Steve'
+ }
+ }
+};
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+ return callback(null, internals.credentials[id]);
+};
+
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
+ var headers = {
+ 'Content-Type': 'text/plain',
+ 'Server-Authorization': Hawk.server.header(credentials, artifacts, { payload: payload, contentType: 'text/plain' })
+ };
+
+ res.writeHead(!err ? 200 : 401, headers);
+ res.end(payload);
+ });
+};
+
+Http.createServer(handler).listen(8000, '127.0.0.1');
+
+
+// Send unauthenticated request
+
+Request('http://127.0.0.1:8000/resource/1?b=1&a=2', function (error, response, body) {
+
+ console.log(response.statusCode + ': ' + body);
+});
+
+
+// Send authenticated request
+
+credentialsFunc('dh37fgj492je', function (err, credentials) {
+
+ var header = Hawk.client.header('http://127.0.0.1:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'and welcome!' });
+ var options = {
+ uri: 'http://127.0.0.1:8000/resource/1?b=1&a=2',
+ method: 'GET',
+ headers: {
+ authorization: header.field
+ }
+ };
+
+ Request(options, function (error, response, body) {
+
+ var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
+ console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
+ process.exit(0);
+ });
+});
+
diff --git a/node_modules/request/node_modules/hawk/images/hawk.png b/node_modules/request/node_modules/hawk/images/hawk.png
new file mode 100755
index 000000000..a0e15cda0
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/images/hawk.png
Binary files differ
diff --git a/node_modules/request/node_modules/hawk/images/logo.png b/node_modules/request/node_modules/hawk/images/logo.png
new file mode 100755
index 000000000..b8ff59017
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/images/logo.png
Binary files differ
diff --git a/node_modules/request/node_modules/hawk/lib/browser.js b/node_modules/request/node_modules/hawk/lib/browser.js
new file mode 100755
index 000000000..7ccacf613
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/browser.js
@@ -0,0 +1,643 @@
+/*
+ HTTP Hawk Authentication Scheme
+ Copyright (c) 2012-2014, Eran Hammer <eran@hammer.io>
+ BSD Licensed
+*/
+
+
+// Declare namespace
+
+var hawk = {
+ internals: {}
+};
+
+
+hawk.client = {
+
+ // Generate an Authorization header for a given request
+
+ /*
+ uri: 'http://example.com/resource?a=b' or object generated by hawk.utils.parseUri()
+ method: HTTP verb (e.g. 'GET', 'POST')
+ options: {
+
+ // Required
+
+ credentials: {
+ id: 'dh37fgj492je',
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+
+ // Optional
+
+ ext: 'application-specific', // Application specific data sent via the ext attribute
+ timestamp: Date.now() / 1000, // A pre-calculated timestamp in seconds
+ nonce: '2334f34f', // A pre-generated nonce
+ localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided)
+ payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided)
+ contentType: 'application/json', // Payload content-type (ignored if hash provided)
+ hash: 'U4MKKSmiVxk37JCCrAVIjV=', // Pre-calculated payload hash
+ app: '24s23423f34dx', // Oz application id
+ dlg: '234sz34tww3sd' // Oz delegated-by application id
+ }
+ */
+
+ header: function (uri, method, options) {
+
+ var result = {
+ field: '',
+ artifacts: {}
+ };
+
+ // Validate inputs
+
+ if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
+ !method || typeof method !== 'string' ||
+ !options || typeof options !== 'object') {
+
+ result.err = 'Invalid argument type';
+ return result;
+ }
+
+ // Application time
+
+ var timestamp = options.timestamp || hawk.utils.now(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ result.err = 'Invalid credentials object';
+ return result;
+ }
+
+ if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ result.err = 'Unknown algorithm';
+ return result;
+ }
+
+ // Parse URI
+
+ if (typeof uri === 'string') {
+ uri = hawk.utils.parseUri(uri);
+ }
+
+ // Calculate signature
+
+ var artifacts = {
+ ts: timestamp,
+ nonce: options.nonce || hawk.utils.randomString(6),
+ method: method,
+ resource: uri.relative,
+ host: uri.hostname,
+ port: uri.port,
+ hash: options.hash,
+ ext: options.ext,
+ app: options.app,
+ dlg: options.dlg
+ };
+
+ result.artifacts = artifacts;
+
+ // Calculate payload hash
+
+ if (!artifacts.hash &&
+ (options.payload || options.payload === '')) {
+
+ artifacts.hash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ }
+
+ var mac = hawk.crypto.calculateMac('header', credentials, artifacts);
+
+ // Construct header
+
+ var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''; // Other falsey values allowed
+ var header = 'Hawk id="' + credentials.id +
+ '", ts="' + artifacts.ts +
+ '", nonce="' + artifacts.nonce +
+ (artifacts.hash ? '", hash="' + artifacts.hash : '') +
+ (hasExt ? '", ext="' + hawk.utils.escapeHeaderAttribute(artifacts.ext) : '') +
+ '", mac="' + mac + '"';
+
+ if (artifacts.app) {
+ header += ', app="' + artifacts.app +
+ (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
+ }
+
+ result.field = header;
+
+ return result;
+ },
+
+ // Generate a bewit value for a given URI
+
+ /*
+ uri: 'http://example.com/resource?a=b'
+ options: {
+
+ // Required
+
+ credentials: {
+ id: 'dh37fgj492je',
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+ ttlSec: 60 * 60, // TTL in seconds
+
+ // Optional
+
+ ext: 'application-specific', // Application specific data sent via the ext attribute
+ localtimeOffsetMsec: 400 // Time offset to sync with server time
+ };
+ */
+
+ bewit: function (uri, options) {
+
+ // Validate inputs
+
+ if (!uri ||
+ (typeof uri !== 'string') ||
+ !options ||
+ typeof options !== 'object' ||
+ !options.ttlSec) {
+
+ return '';
+ }
+
+ options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext); // Zero is valid value
+
+ // Application time
+
+ var now = hawk.utils.now(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ return '';
+ }
+
+ if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return '';
+ }
+
+ // Parse URI
+
+ uri = hawk.utils.parseUri(uri);
+
+ // Calculate signature
+
+ var exp = now + options.ttlSec;
+ var mac = hawk.crypto.calculateMac('bewit', credentials, {
+ ts: exp,
+ nonce: '',
+ method: 'GET',
+ resource: uri.relative, // Maintain trailing '?' and query params
+ host: uri.hostname,
+ port: uri.port,
+ ext: options.ext
+ });
+
+ // Construct bewit: id\exp\mac\ext
+
+ var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext;
+ return hawk.utils.base64urlEncode(bewit);
+ },
+
+ // Validate server response
+
+ /*
+ request: object created via 'new XMLHttpRequest()' after response received
+ artifacts: object received from header().artifacts
+ options: {
+ payload: optional payload received
+ required: specifies if a Server-Authorization header is required. Defaults to 'false'
+ }
+ */
+
+ authenticate: function (request, credentials, artifacts, options) {
+
+ options = options || {};
+
+ var getHeader = function (name) {
+
+ return request.getResponseHeader ? request.getResponseHeader(name) : request.getHeader(name);
+ };
+
+ var wwwAuthenticate = getHeader('www-authenticate');
+ if (wwwAuthenticate) {
+
+ // Parse HTTP WWW-Authenticate header
+
+ var wwwAttributes = hawk.utils.parseAuthorizationHeader(wwwAuthenticate, ['ts', 'tsm', 'error']);
+ if (!wwwAttributes) {
+ return false;
+ }
+
+ if (wwwAttributes.ts) {
+ var tsm = hawk.crypto.calculateTsMac(wwwAttributes.ts, credentials);
+ if (tsm !== wwwAttributes.tsm) {
+ return false;
+ }
+
+ hawk.utils.setNtpOffset(wwwAttributes.ts - Math.floor((new Date()).getTime() / 1000)); // Keep offset at 1 second precision
+ }
+ }
+
+ // Parse HTTP Server-Authorization header
+
+ var serverAuthorization = getHeader('server-authorization');
+ if (!serverAuthorization &&
+ !options.required) {
+
+ return true;
+ }
+
+ var attributes = hawk.utils.parseAuthorizationHeader(serverAuthorization, ['mac', 'ext', 'hash']);
+ if (!attributes) {
+ return false;
+ }
+
+ var modArtifacts = {
+ ts: artifacts.ts,
+ nonce: artifacts.nonce,
+ method: artifacts.method,
+ resource: artifacts.resource,
+ host: artifacts.host,
+ port: artifacts.port,
+ hash: attributes.hash,
+ ext: attributes.ext,
+ app: artifacts.app,
+ dlg: artifacts.dlg
+ };
+
+ var mac = hawk.crypto.calculateMac('response', credentials, modArtifacts);
+ if (mac !== attributes.mac) {
+ return false;
+ }
+
+ if (!options.payload &&
+ options.payload !== '') {
+
+ return true;
+ }
+
+ if (!attributes.hash) {
+ return false;
+ }
+
+ var calculatedHash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, getHeader('content-type'));
+ return (calculatedHash === attributes.hash);
+ },
+
+ message: function (host, port, message, options) {
+
+ // Validate inputs
+
+ if (!host || typeof host !== 'string' ||
+ !port || typeof port !== 'number' ||
+ message === null || message === undefined || typeof message !== 'string' ||
+ !options || typeof options !== 'object') {
+
+ return null;
+ }
+
+ // Application time
+
+ var timestamp = options.timestamp || hawk.utils.now(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ // Invalid credential object
+ return null;
+ }
+
+ if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return null;
+ }
+
+ // Calculate signature
+
+ var artifacts = {
+ ts: timestamp,
+ nonce: options.nonce || hawk.utils.randomString(6),
+ host: host,
+ port: port,
+ hash: hawk.crypto.calculatePayloadHash(message, credentials.algorithm)
+ };
+
+ // Construct authorization
+
+ var result = {
+ id: credentials.id,
+ ts: artifacts.ts,
+ nonce: artifacts.nonce,
+ hash: artifacts.hash,
+ mac: hawk.crypto.calculateMac('message', credentials, artifacts)
+ };
+
+ return result;
+ },
+
+ authenticateTimestamp: function (message, credentials, updateClock) { // updateClock defaults to true
+
+ var tsm = hawk.crypto.calculateTsMac(message.ts, credentials);
+ if (tsm !== message.tsm) {
+ return false;
+ }
+
+ if (updateClock !== false) {
+ hawk.utils.setNtpOffset(message.ts - Math.floor((new Date()).getTime() / 1000)); // Keep offset at 1 second precision
+ }
+
+ return true;
+ }
+};
+
+
+hawk.crypto = {
+
+ headerVersion: '1',
+
+ algorithms: ['sha1', 'sha256'],
+
+ calculateMac: function (type, credentials, options) {
+
+ var normalized = hawk.crypto.generateNormalizedString(type, options);
+
+ var hmac = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()](normalized, credentials.key);
+ return hmac.toString(CryptoJS.enc.Base64);
+ },
+
+ generateNormalizedString: function (type, options) {
+
+ var normalized = 'hawk.' + hawk.crypto.headerVersion + '.' + type + '\n' +
+ options.ts + '\n' +
+ options.nonce + '\n' +
+ (options.method || '').toUpperCase() + '\n' +
+ (options.resource || '') + '\n' +
+ options.host.toLowerCase() + '\n' +
+ options.port + '\n' +
+ (options.hash || '') + '\n';
+
+ if (options.ext) {
+ normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+ }
+
+ normalized += '\n';
+
+ if (options.app) {
+ normalized += options.app + '\n' +
+ (options.dlg || '') + '\n';
+ }
+
+ return normalized;
+ },
+
+ calculatePayloadHash: function (payload, algorithm, contentType) {
+
+ var hash = CryptoJS.algo[algorithm.toUpperCase()].create();
+ hash.update('hawk.' + hawk.crypto.headerVersion + '.payload\n');
+ hash.update(hawk.utils.parseContentType(contentType) + '\n');
+ hash.update(payload);
+ hash.update('\n');
+ return hash.finalize().toString(CryptoJS.enc.Base64);
+ },
+
+ calculateTsMac: function (ts, credentials) {
+
+ var hash = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()]('hawk.' + hawk.crypto.headerVersion + '.ts\n' + ts + '\n', credentials.key);
+ return hash.toString(CryptoJS.enc.Base64);
+ }
+};
+
+
+// localStorage compatible interface
+
+hawk.internals.LocalStorage = function () {
+
+ this._cache = {};
+ this.length = 0;
+
+ this.getItem = function (key) {
+
+ return this._cache.hasOwnProperty(key) ? String(this._cache[key]) : null;
+ };
+
+ this.setItem = function (key, value) {
+
+ this._cache[key] = String(value);
+ this.length = Object.keys(this._cache).length;
+ };
+
+ this.removeItem = function (key) {
+
+ delete this._cache[key];
+ this.length = Object.keys(this._cache).length;
+ };
+
+ this.clear = function () {
+
+ this._cache = {};
+ this.length = 0;
+ };
+
+ this.key = function (i) {
+
+ return Object.keys(this._cache)[i || 0];
+ };
+};
+
+
+hawk.utils = {
+
+ storage: new hawk.internals.LocalStorage(),
+
+ setStorage: function (storage) {
+
+ var ntpOffset = hawk.utils.storage.getItem('hawk_ntp_offset');
+ hawk.utils.storage = storage;
+ if (ntpOffset) {
+ hawk.utils.setNtpOffset(ntpOffset);
+ }
+ },
+
+ setNtpOffset: function (offset) {
+
+ try {
+ hawk.utils.storage.setItem('hawk_ntp_offset', offset);
+ }
+ catch (err) {
+ console.error('[hawk] could not write to storage.');
+ console.error(err);
+ }
+ },
+
+ getNtpOffset: function () {
+
+ var offset = hawk.utils.storage.getItem('hawk_ntp_offset');
+ if (!offset) {
+ return 0;
+ }
+
+ return parseInt(offset, 10);
+ },
+
+ now: function (localtimeOffsetMsec) {
+
+ return Math.floor(((new Date()).getTime() + (localtimeOffsetMsec || 0)) / 1000) + hawk.utils.getNtpOffset();
+ },
+
+ escapeHeaderAttribute: function (attribute) {
+
+ return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');
+ },
+
+ parseContentType: function (header) {
+
+ if (!header) {
+ return '';
+ }
+
+ return header.split(';')[0].replace(/^\s+|\s+$/g, '').toLowerCase();
+ },
+
+ parseAuthorizationHeader: function (header, keys) {
+
+ if (!header) {
+ return null;
+ }
+
+ var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something]
+ if (!headerParts) {
+ return null;
+ }
+
+ var scheme = headerParts[1];
+ if (scheme.toLowerCase() !== 'hawk') {
+ return null;
+ }
+
+ var attributesString = headerParts[2];
+ if (!attributesString) {
+ return null;
+ }
+
+ var attributes = {};
+ var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
+
+ // Check valid attribute names
+
+ if (keys.indexOf($1) === -1) {
+ return;
+ }
+
+ // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
+
+ if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+ return;
+ }
+
+ // Check for duplicates
+
+ if (attributes.hasOwnProperty($1)) {
+ return;
+ }
+
+ attributes[$1] = $2;
+ return '';
+ });
+
+ if (verify !== '') {
+ return null;
+ }
+
+ return attributes;
+ },
+
+ randomString: function (size) {
+
+ var randomSource = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ var len = randomSource.length;
+
+ var result = [];
+ for (var i = 0; i < size; ++i) {
+ result[i] = randomSource[Math.floor(Math.random() * len)];
+ }
+
+ return result.join('');
+ },
+
+ parseUri: function (input) {
+
+ // Based on: parseURI 1.2.2
+ // http://blog.stevenlevithan.com/archives/parseuri
+ // (c) Steven Levithan <stevenlevithan.com>
+ // MIT License
+
+ var keys = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'hostname', 'port', 'resource', 'relative', 'pathname', 'directory', 'file', 'query', 'fragment'];
+
+ var uriRegex = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?)(?:#(.*))?)/;
+ var uriByNumber = input.match(uriRegex);
+ var uri = {};
+
+ for (var i = 0, il = keys.length; i < il; ++i) {
+ uri[keys[i]] = uriByNumber[i] || '';
+ }
+
+ if (uri.port === '') {
+ uri.port = (uri.protocol.toLowerCase() === 'http' ? '80' : (uri.protocol.toLowerCase() === 'https' ? '443' : ''));
+ }
+
+ return uri;
+ },
+
+ base64urlEncode: function (value) {
+
+ var wordArray = CryptoJS.enc.Utf8.parse(value);
+ var encoded = CryptoJS.enc.Base64.stringify(wordArray);
+ return encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
+ }
+};
+
+
+// $lab:coverage:off$
+/* eslint-disable */
+
+// Based on: Crypto-JS v3.1.2
+// Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
+// http://code.google.com/p/crypto-js/
+// http://code.google.com/p/crypto-js/wiki/License
+
+var CryptoJS = CryptoJS || function (h, r) { var k = {}, l = k.lib = {}, n = function () { }, f = l.Base = { extend: function (a) { n.prototype = this; var b = new n; a && b.mixIn(a); b.hasOwnProperty("init") || (b.init = function () { b.$super.init.apply(this, arguments) }); b.init.prototype = b; b.$super = this; return b }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var b in a) a.hasOwnProperty(b) && (this[b] = a[b]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } }, j = l.WordArray = f.extend({ init: function (a, b) { a = this.words = a || []; this.sigBytes = b != r ? b : 4 * a.length }, toString: function (a) { return (a || s).stringify(this) }, concat: function (a) { var b = this.words, d = a.words, c = this.sigBytes; a = a.sigBytes; this.clamp(); if (c % 4) for (var e = 0; e < a; e++) b[c + e >>> 2] |= (d[e >>> 2] >>> 24 - 8 * (e % 4) & 255) << 24 - 8 * ((c + e) % 4); else if (65535 < d.length) for (e = 0; e < a; e += 4) b[c + e >>> 2] = d[e >>> 2]; else b.push.apply(b, d); this.sigBytes += a; return this }, clamp: function () { var a = this.words, b = this.sigBytes; a[b >>> 2] &= 4294967295 << 32 - 8 * (b % 4); a.length = h.ceil(b / 4) }, clone: function () { var a = f.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var b = [], d = 0; d < a; d += 4) b.push(4294967296 * h.random() | 0); return new j.init(b, a) } }), m = k.enc = {}, s = m.Hex = { stringify: function (a) { var b = a.words; a = a.sigBytes; for (var d = [], c = 0; c < a; c++) { var e = b[c >>> 2] >>> 24 - 8 * (c % 4) & 255; d.push((e >>> 4).toString(16)); d.push((e & 15).toString(16)) } return d.join("") }, parse: function (a) { for (var b = a.length, d = [], c = 0; c < b; c += 2) d[c >>> 3] |= parseInt(a.substr(c, 2), 16) << 24 - 4 * (c % 8); return new j.init(d, b / 2) } }, p = m.Latin1 = { stringify: function (a) { var b = a.words; a = a.sigBytes; for (var d = [], c = 0; c < a; c++) d.push(String.fromCharCode(b[c >>> 2] >>> 24 - 8 * (c % 4) & 255)); return d.join("") }, parse: function (a) { for (var b = a.length, d = [], c = 0; c < b; c++) d[c >>> 2] |= (a.charCodeAt(c) & 255) << 24 - 8 * (c % 4); return new j.init(d, b) } }, t = m.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(p.stringify(a))) } catch (b) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return p.parse(unescape(encodeURIComponent(a))) } }, q = l.BufferedBlockAlgorithm = f.extend({ reset: function () { this._data = new j.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = t.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var b = this._data, d = b.words, c = b.sigBytes, e = this.blockSize, f = c / (4 * e), f = a ? h.ceil(f) : h.max((f | 0) - this._minBufferSize, 0); a = f * e; c = h.min(4 * a, c); if (a) { for (var g = 0; g < a; g += e) this._doProcessBlock(d, g); g = d.splice(0, a); b.sigBytes -= c } return new j.init(g, c) }, clone: function () { var a = f.clone.call(this); a._data = this._data.clone(); return a }, _minBufferSize: 0 }); l.Hasher = q.extend({ cfg: f.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { q.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (b, d) { return (new a.init(d)).finalize(b) } }, _createHmacHelper: function (a) { return function (b, d) { return (new u.HMAC.init(a, d)).finalize(b) } } }); var u = k.algo = {}; return k }(Math);
+(function () { var k = CryptoJS, b = k.lib, m = b.WordArray, l = b.Hasher, d = [], b = k.algo.SHA1 = l.extend({ _doReset: function () { this._hash = new m.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (n, p) { for (var a = this._hash.words, e = a[0], f = a[1], h = a[2], j = a[3], b = a[4], c = 0; 80 > c; c++) { if (16 > c) d[c] = n[p + c] | 0; else { var g = d[c - 3] ^ d[c - 8] ^ d[c - 14] ^ d[c - 16]; d[c] = g << 1 | g >>> 31 } g = (e << 5 | e >>> 27) + b + d[c]; g = 20 > c ? g + ((f & h | ~f & j) + 1518500249) : 40 > c ? g + ((f ^ h ^ j) + 1859775393) : 60 > c ? g + ((f & h | f & j | h & j) - 1894007588) : g + ((f ^ h ^ j) - 899497514); b = j; j = h; h = f << 30 | f >>> 2; f = e; e = g } a[0] = a[0] + e | 0; a[1] = a[1] + f | 0; a[2] = a[2] + h | 0; a[3] = a[3] + j | 0; a[4] = a[4] + b | 0 }, _doFinalize: function () { var b = this._data, d = b.words, a = 8 * this._nDataBytes, e = 8 * b.sigBytes; d[e >>> 5] |= 128 << 24 - e % 32; d[(e + 64 >>> 9 << 4) + 14] = Math.floor(a / 4294967296); d[(e + 64 >>> 9 << 4) + 15] = a; b.sigBytes = 4 * d.length; this._process(); return this._hash }, clone: function () { var b = l.clone.call(this); b._hash = this._hash.clone(); return b } }); k.SHA1 = l._createHelper(b); k.HmacSHA1 = l._createHmacHelper(b) })();
+(function (k) { for (var g = CryptoJS, h = g.lib, v = h.WordArray, j = h.Hasher, h = g.algo, s = [], t = [], u = function (q) { return 4294967296 * (q - (q | 0)) | 0 }, l = 2, b = 0; 64 > b;) { var d; a: { d = l; for (var w = k.sqrt(d), r = 2; r <= w; r++) if (!(d % r)) { d = !1; break a } d = !0 } d && (8 > b && (s[b] = u(k.pow(l, 0.5))), t[b] = u(k.pow(l, 1 / 3)), b++); l++ } var n = [], h = h.SHA256 = j.extend({ _doReset: function () { this._hash = new v.init(s.slice(0)) }, _doProcessBlock: function (q, h) { for (var a = this._hash.words, c = a[0], d = a[1], b = a[2], k = a[3], f = a[4], g = a[5], j = a[6], l = a[7], e = 0; 64 > e; e++) { if (16 > e) n[e] = q[h + e] | 0; else { var m = n[e - 15], p = n[e - 2]; n[e] = ((m << 25 | m >>> 7) ^ (m << 14 | m >>> 18) ^ m >>> 3) + n[e - 7] + ((p << 15 | p >>> 17) ^ (p << 13 | p >>> 19) ^ p >>> 10) + n[e - 16] } m = l + ((f << 26 | f >>> 6) ^ (f << 21 | f >>> 11) ^ (f << 7 | f >>> 25)) + (f & g ^ ~f & j) + t[e] + n[e]; p = ((c << 30 | c >>> 2) ^ (c << 19 | c >>> 13) ^ (c << 10 | c >>> 22)) + (c & d ^ c & b ^ d & b); l = j; j = g; g = f; f = k + m | 0; k = b; b = d; d = c; c = m + p | 0 } a[0] = a[0] + c | 0; a[1] = a[1] + d | 0; a[2] = a[2] + b | 0; a[3] = a[3] + k | 0; a[4] = a[4] + f | 0; a[5] = a[5] + g | 0; a[6] = a[6] + j | 0; a[7] = a[7] + l | 0 }, _doFinalize: function () { var d = this._data, b = d.words, a = 8 * this._nDataBytes, c = 8 * d.sigBytes; b[c >>> 5] |= 128 << 24 - c % 32; b[(c + 64 >>> 9 << 4) + 14] = k.floor(a / 4294967296); b[(c + 64 >>> 9 << 4) + 15] = a; d.sigBytes = 4 * b.length; this._process(); return this._hash }, clone: function () { var b = j.clone.call(this); b._hash = this._hash.clone(); return b } }); g.SHA256 = j._createHelper(h); g.HmacSHA256 = j._createHmacHelper(h) })(Math);
+(function () { var c = CryptoJS, k = c.enc.Utf8; c.algo.HMAC = c.lib.Base.extend({ init: function (a, b) { a = this._hasher = new a.init; "string" == typeof b && (b = k.parse(b)); var c = a.blockSize, e = 4 * c; b.sigBytes > e && (b = a.finalize(b)); b.clamp(); for (var f = this._oKey = b.clone(), g = this._iKey = b.clone(), h = f.words, j = g.words, d = 0; d < c; d++) h[d] ^= 1549556828, j[d] ^= 909522486; f.sigBytes = g.sigBytes = e; this.reset() }, reset: function () { var a = this._hasher; a.reset(); a.update(this._iKey) }, update: function (a) { this._hasher.update(a); return this }, finalize: function (a) { var b = this._hasher; a = b.finalize(a); b.reset(); return b.finalize(this._oKey.clone().concat(a)) } }) })();
+(function () { var h = CryptoJS, j = h.lib.WordArray; h.enc.Base64 = { stringify: function (b) { var e = b.words, f = b.sigBytes, c = this._map; b.clamp(); b = []; for (var a = 0; a < f; a += 3) for (var d = (e[a >>> 2] >>> 24 - 8 * (a % 4) & 255) << 16 | (e[a + 1 >>> 2] >>> 24 - 8 * ((a + 1) % 4) & 255) << 8 | e[a + 2 >>> 2] >>> 24 - 8 * ((a + 2) % 4) & 255, g = 0; 4 > g && a + 0.75 * g < f; g++) b.push(c.charAt(d >>> 6 * (3 - g) & 63)); if (e = c.charAt(64)) for (; b.length % 4;) b.push(e); return b.join("") }, parse: function (b) { var e = b.length, f = this._map, c = f.charAt(64); c && (c = b.indexOf(c), -1 != c && (e = c)); for (var c = [], a = 0, d = 0; d < e; d++) if (d % 4) { var g = f.indexOf(b.charAt(d - 1)) << 2 * (d % 4), h = f.indexOf(b.charAt(d)) >>> 6 - 2 * (d % 4); c[a >>> 2] |= (g | h) << 24 - 8 * (a % 4); a++ } return j.create(c, a) }, _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" } })();
+
+hawk.crypto.internals = CryptoJS;
+
+
+// Export if used as a module
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = hawk;
+}
+
+/* eslint-enable */
+// $lab:coverage:on$
diff --git a/node_modules/request/node_modules/hawk/lib/client.js b/node_modules/request/node_modules/hawk/lib/client.js
new file mode 100755
index 000000000..b3e8649e3
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/client.js
@@ -0,0 +1,369 @@
+// Load modules
+
+var Url = require('url');
+var Hoek = require('hoek');
+var Cryptiles = require('cryptiles');
+var Crypto = require('./crypto');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Generate an Authorization header for a given request
+
+/*
+ uri: 'http://example.com/resource?a=b' or object from Url.parse()
+ method: HTTP verb (e.g. 'GET', 'POST')
+ options: {
+
+ // Required
+
+ credentials: {
+ id: 'dh37fgj492je',
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+
+ // Optional
+
+ ext: 'application-specific', // Application specific data sent via the ext attribute
+ timestamp: Date.now(), // A pre-calculated timestamp
+ nonce: '2334f34f', // A pre-generated nonce
+ localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided)
+ payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided)
+ contentType: 'application/json', // Payload content-type (ignored if hash provided)
+ hash: 'U4MKKSmiVxk37JCCrAVIjV=', // Pre-calculated payload hash
+ app: '24s23423f34dx', // Oz application id
+ dlg: '234sz34tww3sd' // Oz delegated-by application id
+ }
+*/
+
+exports.header = function (uri, method, options) {
+
+ var result = {
+ field: '',
+ artifacts: {}
+ };
+
+ // Validate inputs
+
+ if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
+ !method || typeof method !== 'string' ||
+ !options || typeof options !== 'object') {
+
+ result.err = 'Invalid argument type';
+ return result;
+ }
+
+ // Application time
+
+ var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ result.err = 'Invalid credential object';
+ return result;
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ result.err = 'Unknown algorithm';
+ return result;
+ }
+
+ // Parse URI
+
+ if (typeof uri === 'string') {
+ uri = Url.parse(uri);
+ }
+
+ // Calculate signature
+
+ var artifacts = {
+ ts: timestamp,
+ nonce: options.nonce || Cryptiles.randomString(6),
+ method: method,
+ resource: uri.pathname + (uri.search || ''), // Maintain trailing '?'
+ host: uri.hostname,
+ port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
+ hash: options.hash,
+ ext: options.ext,
+ app: options.app,
+ dlg: options.dlg
+ };
+
+ result.artifacts = artifacts;
+
+ // Calculate payload hash
+
+ if (!artifacts.hash &&
+ (options.payload || options.payload === '')) {
+
+ artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ }
+
+ var mac = Crypto.calculateMac('header', credentials, artifacts);
+
+ // Construct header
+
+ var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''; // Other falsey values allowed
+ var header = 'Hawk id="' + credentials.id +
+ '", ts="' + artifacts.ts +
+ '", nonce="' + artifacts.nonce +
+ (artifacts.hash ? '", hash="' + artifacts.hash : '') +
+ (hasExt ? '", ext="' + Hoek.escapeHeaderAttribute(artifacts.ext) : '') +
+ '", mac="' + mac + '"';
+
+ if (artifacts.app) {
+ header += ', app="' + artifacts.app +
+ (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
+ }
+
+ result.field = header;
+
+ return result;
+};
+
+
+// Validate server response
+
+/*
+ res: node's response object
+ artifacts: object received from header().artifacts
+ options: {
+ payload: optional payload received
+ required: specifies if a Server-Authorization header is required. Defaults to 'false'
+ }
+*/
+
+exports.authenticate = function (res, credentials, artifacts, options) {
+
+ artifacts = Hoek.clone(artifacts);
+ options = options || {};
+
+ if (res.headers['www-authenticate']) {
+
+ // Parse HTTP WWW-Authenticate header
+
+ var wwwAttributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']);
+ if (wwwAttributes instanceof Error) {
+ return false;
+ }
+
+ // Validate server timestamp (not used to update clock since it is done via the SNPT client)
+
+ if (wwwAttributes.ts) {
+ var tsm = Crypto.calculateTsMac(wwwAttributes.ts, credentials);
+ if (tsm !== wwwAttributes.tsm) {
+ return false;
+ }
+ }
+ }
+
+ // Parse HTTP Server-Authorization header
+
+ if (!res.headers['server-authorization'] &&
+ !options.required) {
+
+ return true;
+ }
+
+ var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']);
+ if (attributes instanceof Error) {
+ return false;
+ }
+
+ artifacts.ext = attributes.ext;
+ artifacts.hash = attributes.hash;
+
+ var mac = Crypto.calculateMac('response', credentials, artifacts);
+ if (mac !== attributes.mac) {
+ return false;
+ }
+
+ if (!options.payload &&
+ options.payload !== '') {
+
+ return true;
+ }
+
+ if (!attributes.hash) {
+ return false;
+ }
+
+ var calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']);
+ return (calculatedHash === attributes.hash);
+};
+
+
+// Generate a bewit value for a given URI
+
+/*
+ uri: 'http://example.com/resource?a=b' or object from Url.parse()
+ options: {
+
+ // Required
+
+ credentials: {
+ id: 'dh37fgj492je',
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+ ttlSec: 60 * 60, // TTL in seconds
+
+ // Optional
+
+ ext: 'application-specific', // Application specific data sent via the ext attribute
+ localtimeOffsetMsec: 400 // Time offset to sync with server time
+ };
+*/
+
+exports.getBewit = function (uri, options) {
+
+ // Validate inputs
+
+ if (!uri ||
+ (typeof uri !== 'string' && typeof uri !== 'object') ||
+ !options ||
+ typeof options !== 'object' ||
+ !options.ttlSec) {
+
+ return '';
+ }
+
+ options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext); // Zero is valid value
+
+ // Application time
+
+ var now = Utils.now(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ return '';
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return '';
+ }
+
+ // Parse URI
+
+ if (typeof uri === 'string') {
+ uri = Url.parse(uri);
+ }
+
+ // Calculate signature
+
+ var exp = Math.floor(now / 1000) + options.ttlSec;
+ var mac = Crypto.calculateMac('bewit', credentials, {
+ ts: exp,
+ nonce: '',
+ method: 'GET',
+ resource: uri.pathname + (uri.search || ''), // Maintain trailing '?'
+ host: uri.hostname,
+ port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
+ ext: options.ext
+ });
+
+ // Construct bewit: id\exp\mac\ext
+
+ var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext;
+ return Hoek.base64urlEncode(bewit);
+};
+
+
+// Generate an authorization string for a message
+
+/*
+ host: 'example.com',
+ port: 8000,
+ message: '{"some":"payload"}', // UTF-8 encoded string for body hash generation
+ options: {
+
+ // Required
+
+ credentials: {
+ id: 'dh37fgj492je',
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+
+ // Optional
+
+ timestamp: Date.now(), // A pre-calculated timestamp
+ nonce: '2334f34f', // A pre-generated nonce
+ localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided)
+ }
+*/
+
+exports.message = function (host, port, message, options) {
+
+ // Validate inputs
+
+ if (!host || typeof host !== 'string' ||
+ !port || typeof port !== 'number' ||
+ message === null || message === undefined || typeof message !== 'string' ||
+ !options || typeof options !== 'object') {
+
+ return null;
+ }
+
+ // Application time
+
+ var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
+
+ // Validate credentials
+
+ var credentials = options.credentials;
+ if (!credentials ||
+ !credentials.id ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ // Invalid credential object
+ return null;
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return null;
+ }
+
+ // Calculate signature
+
+ var artifacts = {
+ ts: timestamp,
+ nonce: options.nonce || Cryptiles.randomString(6),
+ host: host,
+ port: port,
+ hash: Crypto.calculatePayloadHash(message, credentials.algorithm)
+ };
+
+ // Construct authorization
+
+ var result = {
+ id: credentials.id,
+ ts: artifacts.ts,
+ nonce: artifacts.nonce,
+ hash: artifacts.hash,
+ mac: Crypto.calculateMac('message', credentials, artifacts)
+ };
+
+ return result;
+};
+
+
+
diff --git a/node_modules/request/node_modules/hawk/lib/crypto.js b/node_modules/request/node_modules/hawk/lib/crypto.js
new file mode 100755
index 000000000..d3c8244a9
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/crypto.js
@@ -0,0 +1,126 @@
+// Load modules
+
+var Crypto = require('crypto');
+var Url = require('url');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// MAC normalization format version
+
+exports.headerVersion = '1'; // Prevent comparison of mac values generated with different normalized string formats
+
+
+// Supported HMAC algorithms
+
+exports.algorithms = ['sha1', 'sha256'];
+
+
+// Calculate the request MAC
+
+/*
+ type: 'header', // 'header', 'bewit', 'response'
+ credentials: {
+ key: 'aoijedoaijsdlaksjdl',
+ algorithm: 'sha256' // 'sha1', 'sha256'
+ },
+ options: {
+ method: 'GET',
+ resource: '/resource?a=1&b=2',
+ host: 'example.com',
+ port: 8080,
+ ts: 1357718381034,
+ nonce: 'd3d345f',
+ hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=',
+ ext: 'app-specific-data',
+ app: 'hf48hd83qwkj', // Application id (Oz)
+ dlg: 'd8djwekds9cj' // Delegated by application id (Oz), requires options.app
+ }
+*/
+
+exports.calculateMac = function (type, credentials, options) {
+
+ var normalized = exports.generateNormalizedString(type, options);
+
+ var hmac = Crypto.createHmac(credentials.algorithm, credentials.key).update(normalized);
+ var digest = hmac.digest('base64');
+ return digest;
+};
+
+
+exports.generateNormalizedString = function (type, options) {
+
+ var resource = options.resource || '';
+ if (resource &&
+ resource[0] !== '/') {
+
+ var url = Url.parse(resource, false);
+ resource = url.path; // Includes query
+ }
+
+ var normalized = 'hawk.' + exports.headerVersion + '.' + type + '\n' +
+ options.ts + '\n' +
+ options.nonce + '\n' +
+ (options.method || '').toUpperCase() + '\n' +
+ resource + '\n' +
+ options.host.toLowerCase() + '\n' +
+ options.port + '\n' +
+ (options.hash || '') + '\n';
+
+ if (options.ext) {
+ normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+ }
+
+ normalized += '\n';
+
+ if (options.app) {
+ normalized += options.app + '\n' +
+ (options.dlg || '') + '\n';
+ }
+
+ return normalized;
+};
+
+
+exports.calculatePayloadHash = function (payload, algorithm, contentType) {
+
+ var hash = exports.initializePayloadHash(algorithm, contentType);
+ hash.update(payload || '');
+ return exports.finalizePayloadHash(hash);
+};
+
+
+exports.initializePayloadHash = function (algorithm, contentType) {
+
+ var hash = Crypto.createHash(algorithm);
+ hash.update('hawk.' + exports.headerVersion + '.payload\n');
+ hash.update(Utils.parseContentType(contentType) + '\n');
+ return hash;
+};
+
+
+exports.finalizePayloadHash = function (hash) {
+
+ hash.update('\n');
+ return hash.digest('base64');
+};
+
+
+exports.calculateTsMac = function (ts, credentials) {
+
+ var hmac = Crypto.createHmac(credentials.algorithm, credentials.key);
+ hmac.update('hawk.' + exports.headerVersion + '.ts\n' + ts + '\n');
+ return hmac.digest('base64');
+};
+
+
+exports.timestampMessage = function (credentials, localtimeOffsetMsec) {
+
+ var now = Utils.nowSecs(localtimeOffsetMsec);
+ var tsm = exports.calculateTsMac(now, credentials);
+ return { ts: now, tsm: tsm };
+};
diff --git a/node_modules/request/node_modules/hawk/lib/index.js b/node_modules/request/node_modules/hawk/lib/index.js
new file mode 100755
index 000000000..a883882c8
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/index.js
@@ -0,0 +1,15 @@
+// Export sub-modules
+
+exports.error = exports.Error = require('boom');
+exports.sntp = require('sntp');
+
+exports.server = require('./server');
+exports.client = require('./client');
+exports.crypto = require('./crypto');
+exports.utils = require('./utils');
+
+exports.uri = {
+ authenticate: exports.server.authenticateBewit,
+ getBewit: exports.client.getBewit
+};
+
diff --git a/node_modules/request/node_modules/hawk/lib/server.js b/node_modules/request/node_modules/hawk/lib/server.js
new file mode 100755
index 000000000..a325d56a5
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/server.js
@@ -0,0 +1,540 @@
+// Load modules
+
+var Boom = require('boom');
+var Hoek = require('hoek');
+var Cryptiles = require('cryptiles');
+var Crypto = require('./crypto');
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Hawk authentication
+
+/*
+ req: node's HTTP request object or an object as follows:
+
+ var request = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="'
+ };
+
+ credentialsFunc: required function to lookup the set of Hawk credentials based on the provided credentials id.
+ The credentials include the MAC key, MAC algorithm, and other attributes (such as username)
+ needed by the application. This function is the equivalent of verifying the username and
+ password in Basic authentication.
+
+ var credentialsFunc = function (id, callback) {
+
+ // Lookup credentials in database
+ db.lookup(id, function (err, item) {
+
+ if (err || !item) {
+ return callback(err);
+ }
+
+ var credentials = {
+ // Required
+ key: item.key,
+ algorithm: item.algorithm,
+ // Application specific
+ user: item.user
+ };
+
+ return callback(null, credentials);
+ });
+ };
+
+ options: {
+
+ hostHeaderName: optional header field name, used to override the default 'Host' header when used
+ behind a cache of a proxy. Apache2 changes the value of the 'Host' header while preserving
+ the original (which is what the module must verify) in the 'x-forwarded-host' header field.
+ Only used when passed a node Http.ServerRequest object.
+
+ nonceFunc: optional nonce validation function. The function signature is function(key, nonce, ts, callback)
+ where 'callback' must be called using the signature function(err).
+
+ timestampSkewSec: optional number of seconds of permitted clock skew for incoming timestamps. Defaults to 60 seconds.
+ Provides a +/- skew which means actual allowed window is double the number of seconds.
+
+ localtimeOffsetMsec: optional local clock time offset express in a number of milliseconds (positive or negative).
+ Defaults to 0.
+
+ payload: optional payload for validation. The client calculates the hash value and includes it via the 'hash'
+ header attribute. The server always ensures the value provided has been included in the request
+ MAC. When this option is provided, it validates the hash value itself. Validation is done by calculating
+ a hash value over the entire payload (assuming it has already be normalized to the same format and
+ encoding used by the client to calculate the hash on request). If the payload is not available at the time
+ of authentication, the authenticatePayload() method can be used by passing it the credentials and
+ attributes.hash returned in the authenticate callback.
+
+ host: optional host name override. Only used when passed a node request object.
+ port: optional port override. Only used when passed a node request object.
+ }
+
+ callback: function (err, credentials, artifacts) { }
+ */
+
+exports.authenticate = function (req, credentialsFunc, options, callback) {
+
+ callback = Hoek.nextTick(callback);
+
+ // Default options
+
+ options.nonceFunc = options.nonceFunc || internals.nonceFunc;
+ options.timestampSkewSec = options.timestampSkewSec || 60; // 60 seconds
+
+ // Application time
+
+ var now = Utils.now(options.localtimeOffsetMsec); // Measure now before any other processing
+
+ // Convert node Http request object to a request configuration object
+
+ var request = Utils.parseRequest(req, options);
+ if (request instanceof Error) {
+ return callback(Boom.badRequest(request.message));
+ }
+
+ // Parse HTTP Authorization header
+
+ var attributes = Utils.parseAuthorizationHeader(request.authorization);
+ if (attributes instanceof Error) {
+ return callback(attributes);
+ }
+
+ // Construct artifacts container
+
+ var artifacts = {
+ method: request.method,
+ host: request.host,
+ port: request.port,
+ resource: request.url,
+ ts: attributes.ts,
+ nonce: attributes.nonce,
+ hash: attributes.hash,
+ ext: attributes.ext,
+ app: attributes.app,
+ dlg: attributes.dlg,
+ mac: attributes.mac,
+ id: attributes.id
+ };
+
+ // Verify required header attributes
+
+ if (!attributes.id ||
+ !attributes.ts ||
+ !attributes.nonce ||
+ !attributes.mac) {
+
+ return callback(Boom.badRequest('Missing attributes'), null, artifacts);
+ }
+
+ // Fetch Hawk credentials
+
+ credentialsFunc(attributes.id, function (err, credentials) {
+
+ if (err) {
+ return callback(err, credentials || null, artifacts);
+ }
+
+ if (!credentials) {
+ return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, artifacts);
+ }
+
+ if (!credentials.key ||
+ !credentials.algorithm) {
+
+ return callback(Boom.internal('Invalid credentials'), credentials, artifacts);
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return callback(Boom.internal('Unknown algorithm'), credentials, artifacts);
+ }
+
+ // Calculate MAC
+
+ var mac = Crypto.calculateMac('header', credentials, artifacts);
+ if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) {
+ return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, artifacts);
+ }
+
+ // Check payload hash
+
+ if (options.payload ||
+ options.payload === '') {
+
+ if (!attributes.hash) {
+ return callback(Boom.unauthorized('Missing required payload hash', 'Hawk'), credentials, artifacts);
+ }
+
+ var hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, request.contentType);
+ if (!Cryptiles.fixedTimeComparison(hash, attributes.hash)) {
+ return callback(Boom.unauthorized('Bad payload hash', 'Hawk'), credentials, artifacts);
+ }
+ }
+
+ // Check nonce
+
+ options.nonceFunc(credentials.key, attributes.nonce, attributes.ts, function (err) {
+
+ if (err) {
+ return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials, artifacts);
+ }
+
+ // Check timestamp staleness
+
+ if (Math.abs((attributes.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
+ var tsm = Crypto.timestampMessage(credentials, options.localtimeOffsetMsec);
+ return callback(Boom.unauthorized('Stale timestamp', 'Hawk', tsm), credentials, artifacts);
+ }
+
+ // Successful authentication
+
+ return callback(null, credentials, artifacts);
+ });
+ });
+};
+
+
+// Authenticate payload hash - used when payload cannot be provided during authenticate()
+
+/*
+ payload: raw request payload
+ credentials: from authenticate callback
+ artifacts: from authenticate callback
+ contentType: req.headers['content-type']
+*/
+
+exports.authenticatePayload = function (payload, credentials, artifacts, contentType) {
+
+ var calculatedHash = Crypto.calculatePayloadHash(payload, credentials.algorithm, contentType);
+ return Cryptiles.fixedTimeComparison(calculatedHash, artifacts.hash);
+};
+
+
+// Authenticate payload hash - used when payload cannot be provided during authenticate()
+
+/*
+ calculatedHash: the payload hash calculated using Crypto.calculatePayloadHash()
+ artifacts: from authenticate callback
+*/
+
+exports.authenticatePayloadHash = function (calculatedHash, artifacts) {
+
+ return Cryptiles.fixedTimeComparison(calculatedHash, artifacts.hash);
+};
+
+
+// Generate a Server-Authorization header for a given response
+
+/*
+ credentials: {}, // Object received from authenticate()
+ artifacts: {} // Object received from authenticate(); 'mac', 'hash', and 'ext' - ignored
+ options: {
+ ext: 'application-specific', // Application specific data sent via the ext attribute
+ payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided)
+ contentType: 'application/json', // Payload content-type (ignored if hash provided)
+ hash: 'U4MKKSmiVxk37JCCrAVIjV=' // Pre-calculated payload hash
+ }
+*/
+
+exports.header = function (credentials, artifacts, options) {
+
+ // Prepare inputs
+
+ options = options || {};
+
+ if (!artifacts ||
+ typeof artifacts !== 'object' ||
+ typeof options !== 'object') {
+
+ return '';
+ }
+
+ artifacts = Hoek.clone(artifacts);
+ delete artifacts.mac;
+ artifacts.hash = options.hash;
+ artifacts.ext = options.ext;
+
+ // Validate credentials
+
+ if (!credentials ||
+ !credentials.key ||
+ !credentials.algorithm) {
+
+ // Invalid credential object
+ return '';
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return '';
+ }
+
+ // Calculate payload hash
+
+ if (!artifacts.hash &&
+ (options.payload || options.payload === '')) {
+
+ artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ }
+
+ var mac = Crypto.calculateMac('response', credentials, artifacts);
+
+ // Construct header
+
+ var header = 'Hawk mac="' + mac + '"' +
+ (artifacts.hash ? ', hash="' + artifacts.hash + '"' : '');
+
+ if (artifacts.ext !== null &&
+ artifacts.ext !== undefined &&
+ artifacts.ext !== '') { // Other falsey values allowed
+
+ header += ', ext="' + Hoek.escapeHeaderAttribute(artifacts.ext) + '"';
+ }
+
+ return header;
+};
+
+
+/*
+ * Arguments and options are the same as authenticate() with the exception that the only supported options are:
+ * 'hostHeaderName', 'localtimeOffsetMsec', 'host', 'port'
+ */
+
+exports.authenticateBewit = function (req, credentialsFunc, options, callback) {
+
+ callback = Hoek.nextTick(callback);
+
+ // Application time
+
+ var now = Utils.now(options.localtimeOffsetMsec);
+
+ // Convert node Http request object to a request configuration object
+
+ var request = Utils.parseRequest(req, options);
+ if (request instanceof Error) {
+ return callback(Boom.badRequest(request.message));
+ }
+
+ // Extract bewit
+
+ // 1 2 3 4
+ var resource = request.url.match(/^(\/.*)([\?&])bewit\=([^&$]*)(?:&(.+))?$/);
+ if (!resource) {
+ return callback(Boom.unauthorized(null, 'Hawk'));
+ }
+
+ // Bewit not empty
+
+ if (!resource[3]) {
+ return callback(Boom.unauthorized('Empty bewit', 'Hawk'));
+ }
+
+ // Verify method is GET
+
+ if (request.method !== 'GET' &&
+ request.method !== 'HEAD') {
+
+ return callback(Boom.unauthorized('Invalid method', 'Hawk'));
+ }
+
+ // No other authentication
+
+ if (request.authorization) {
+ return callback(Boom.badRequest('Multiple authentications'));
+ }
+
+ // Parse bewit
+
+ var bewitString = Hoek.base64urlDecode(resource[3]);
+ if (bewitString instanceof Error) {
+ return callback(Boom.badRequest('Invalid bewit encoding'));
+ }
+
+ // Bewit format: id\exp\mac\ext ('\' is used because it is a reserved header attribute character)
+
+ var bewitParts = bewitString.split('\\');
+ if (bewitParts.length !== 4) {
+ return callback(Boom.badRequest('Invalid bewit structure'));
+ }
+
+ var bewit = {
+ id: bewitParts[0],
+ exp: parseInt(bewitParts[1], 10),
+ mac: bewitParts[2],
+ ext: bewitParts[3] || ''
+ };
+
+ if (!bewit.id ||
+ !bewit.exp ||
+ !bewit.mac) {
+
+ return callback(Boom.badRequest('Missing bewit attributes'));
+ }
+
+ // Construct URL without bewit
+
+ var url = resource[1];
+ if (resource[4]) {
+ url += resource[2] + resource[4];
+ }
+
+ // Check expiration
+
+ if (bewit.exp * 1000 <= now) {
+ return callback(Boom.unauthorized('Access expired', 'Hawk'), null, bewit);
+ }
+
+ // Fetch Hawk credentials
+
+ credentialsFunc(bewit.id, function (err, credentials) {
+
+ if (err) {
+ return callback(err, credentials || null, bewit.ext);
+ }
+
+ if (!credentials) {
+ return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, bewit);
+ }
+
+ if (!credentials.key ||
+ !credentials.algorithm) {
+
+ return callback(Boom.internal('Invalid credentials'), credentials, bewit);
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return callback(Boom.internal('Unknown algorithm'), credentials, bewit);
+ }
+
+ // Calculate MAC
+
+ var mac = Crypto.calculateMac('bewit', credentials, {
+ ts: bewit.exp,
+ nonce: '',
+ method: 'GET',
+ resource: url,
+ host: request.host,
+ port: request.port,
+ ext: bewit.ext
+ });
+
+ if (!Cryptiles.fixedTimeComparison(mac, bewit.mac)) {
+ return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, bewit);
+ }
+
+ // Successful authentication
+
+ return callback(null, credentials, bewit);
+ });
+};
+
+
+/*
+ * options are the same as authenticate() with the exception that the only supported options are:
+ * 'nonceFunc', 'timestampSkewSec', 'localtimeOffsetMsec'
+ */
+
+exports.authenticateMessage = function (host, port, message, authorization, credentialsFunc, options, callback) {
+
+ callback = Hoek.nextTick(callback);
+
+ // Default options
+
+ options.nonceFunc = options.nonceFunc || internals.nonceFunc;
+ options.timestampSkewSec = options.timestampSkewSec || 60; // 60 seconds
+
+ // Application time
+
+ var now = Utils.now(options.localtimeOffsetMsec); // Measure now before any other processing
+
+ // Validate authorization
+
+ if (!authorization.id ||
+ !authorization.ts ||
+ !authorization.nonce ||
+ !authorization.hash ||
+ !authorization.mac) {
+
+ return callback(Boom.badRequest('Invalid authorization'));
+ }
+
+ // Fetch Hawk credentials
+
+ credentialsFunc(authorization.id, function (err, credentials) {
+
+ if (err) {
+ return callback(err, credentials || null);
+ }
+
+ if (!credentials) {
+ return callback(Boom.unauthorized('Unknown credentials', 'Hawk'));
+ }
+
+ if (!credentials.key ||
+ !credentials.algorithm) {
+
+ return callback(Boom.internal('Invalid credentials'), credentials);
+ }
+
+ if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return callback(Boom.internal('Unknown algorithm'), credentials);
+ }
+
+ // Construct artifacts container
+
+ var artifacts = {
+ ts: authorization.ts,
+ nonce: authorization.nonce,
+ host: host,
+ port: port,
+ hash: authorization.hash
+ };
+
+ // Calculate MAC
+
+ var mac = Crypto.calculateMac('message', credentials, artifacts);
+ if (!Cryptiles.fixedTimeComparison(mac, authorization.mac)) {
+ return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials);
+ }
+
+ // Check payload hash
+
+ var hash = Crypto.calculatePayloadHash(message, credentials.algorithm);
+ if (!Cryptiles.fixedTimeComparison(hash, authorization.hash)) {
+ return callback(Boom.unauthorized('Bad message hash', 'Hawk'), credentials);
+ }
+
+ // Check nonce
+
+ options.nonceFunc(credentials.key, authorization.nonce, authorization.ts, function (err) {
+
+ if (err) {
+ return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials);
+ }
+
+ // Check timestamp staleness
+
+ if (Math.abs((authorization.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
+ return callback(Boom.unauthorized('Stale timestamp'), credentials);
+ }
+
+ // Successful authentication
+
+ return callback(null, credentials);
+ });
+ });
+};
+
+
+internals.nonceFunc = function (key, nonce, ts, nonceCallback) {
+
+ return nonceCallback(); // No validation
+};
diff --git a/node_modules/request/node_modules/hawk/lib/utils.js b/node_modules/request/node_modules/hawk/lib/utils.js
new file mode 100755
index 000000000..8d2719abc
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/lib/utils.js
@@ -0,0 +1,164 @@
+// Load modules
+
+var Sntp = require('sntp');
+var Boom = require('boom');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports.version = function () {
+
+ return require('../package.json').version;
+};
+
+
+// Extract host and port from request
+
+// $1 $2
+internals.hostHeaderRegex = /^(?:(?:\r\n)?\s)*((?:[^:]+)|(?:\[[^\]]+\]))(?::(\d+))?(?:(?:\r\n)?\s)*$/; // (IPv4, hostname)|(IPv6)
+
+
+exports.parseHost = function (req, hostHeaderName) {
+
+ hostHeaderName = (hostHeaderName ? hostHeaderName.toLowerCase() : 'host');
+ var hostHeader = req.headers[hostHeaderName];
+ if (!hostHeader) {
+ return null;
+ }
+
+ var hostParts = hostHeader.match(internals.hostHeaderRegex);
+ if (!hostParts) {
+ return null;
+ }
+
+ return {
+ name: hostParts[1],
+ port: (hostParts[2] ? hostParts[2] : (req.connection && req.connection.encrypted ? 443 : 80))
+ };
+};
+
+
+// Parse Content-Type header content
+
+exports.parseContentType = function (header) {
+
+ if (!header) {
+ return '';
+ }
+
+ return header.split(';')[0].trim().toLowerCase();
+};
+
+
+// Convert node's to request configuration object
+
+exports.parseRequest = function (req, options) {
+
+ if (!req.headers) {
+ return req;
+ }
+
+ // Obtain host and port information
+
+ if (!options.host || !options.port) {
+ var host = exports.parseHost(req, options.hostHeaderName);
+ if (!host) {
+ return new Error('Invalid Host header');
+ }
+ }
+
+ var request = {
+ method: req.method,
+ url: req.url,
+ host: options.host || host.name,
+ port: options.port || host.port,
+ authorization: req.headers.authorization,
+ contentType: req.headers['content-type'] || ''
+ };
+
+ return request;
+};
+
+
+exports.now = function (localtimeOffsetMsec) {
+
+ return Sntp.now() + (localtimeOffsetMsec || 0);
+};
+
+
+exports.nowSecs = function (localtimeOffsetMsec) {
+
+ return Math.floor(exports.now(localtimeOffsetMsec) / 1000);
+};
+
+
+// Parse Hawk HTTP Authorization header
+
+exports.parseAuthorizationHeader = function (header, keys) {
+
+ keys = keys || ['id', 'ts', 'nonce', 'hash', 'ext', 'mac', 'app', 'dlg'];
+
+ if (!header) {
+ return Boom.unauthorized(null, 'Hawk');
+ }
+
+ var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something]
+ if (!headerParts) {
+ return Boom.badRequest('Invalid header syntax');
+ }
+
+ var scheme = headerParts[1];
+ if (scheme.toLowerCase() !== 'hawk') {
+ return Boom.unauthorized(null, 'Hawk');
+ }
+
+ var attributesString = headerParts[2];
+ if (!attributesString) {
+ return Boom.badRequest('Invalid header syntax');
+ }
+
+ var attributes = {};
+ var errorMessage = '';
+ var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
+
+ // Check valid attribute names
+
+ if (keys.indexOf($1) === -1) {
+ errorMessage = 'Unknown attribute: ' + $1;
+ return;
+ }
+
+ // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
+
+ if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+ errorMessage = 'Bad attribute value: ' + $1;
+ return;
+ }
+
+ // Check for duplicates
+
+ if (attributes.hasOwnProperty($1)) {
+ errorMessage = 'Duplicate attribute: ' + $1;
+ return;
+ }
+
+ attributes[$1] = $2;
+ return '';
+ });
+
+ if (verify !== '') {
+ return Boom.badRequest(errorMessage || 'Bad header format');
+ }
+
+ return attributes;
+};
+
+
+exports.unauthorized = function (message, attributes) {
+
+ return Boom.unauthorized(message, 'Hawk', attributes);
+};
+
diff --git a/node_modules/request/node_modules/hawk/package.json b/node_modules/request/node_modules/hawk/package.json
new file mode 100644
index 000000000..97f459940
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/package.json
@@ -0,0 +1,91 @@
+{
+ "_args": [
+ [
+ "hawk@~3.1.0",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "hawk@>=3.1.0 <3.2.0",
+ "_id": "hawk@3.1.0",
+ "_inCache": true,
+ "_location": "/request/hawk",
+ "_nodeVersion": "0.10.38",
+ "_npmUser": {
+ "email": "eran@hammer.io",
+ "name": "hueniverse"
+ },
+ "_npmVersion": "2.10.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "hawk",
+ "raw": "hawk@~3.1.0",
+ "rawSpec": "~3.1.0",
+ "scope": null,
+ "spec": ">=3.1.0 <3.2.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz",
+ "_shasum": "8a13ae19977ec607602f3f0b9fd676f18c384e44",
+ "_shrinkwrap": null,
+ "_spec": "hawk@~3.1.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "author": {
+ "email": "eran@hammer.io",
+ "name": "Eran Hammer",
+ "url": "http://hueniverse.com"
+ },
+ "browser": "./lib/browser.js",
+ "bugs": {
+ "url": "https://github.com/hueniverse/hawk/issues"
+ },
+ "contributors": [],
+ "dependencies": {
+ "boom": "^2.8.x",
+ "cryptiles": "2.x.x",
+ "hoek": "2.x.x",
+ "sntp": "1.x.x"
+ },
+ "description": "HTTP Hawk Authentication Scheme",
+ "devDependencies": {
+ "code": "1.x.x",
+ "lab": "5.x.x"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "8a13ae19977ec607602f3f0b9fd676f18c384e44",
+ "tarball": "http://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+ },
+ "engines": {
+ "node": ">=0.10.32"
+ },
+ "gitHead": "fdb9d05e383d5237631eaddc4f51422e54fa8b52",
+ "homepage": "https://github.com/hueniverse/hawk#readme",
+ "keywords": [
+ "authentication",
+ "hawk",
+ "http",
+ "scheme"
+ ],
+ "license": "BSD-3-Clause",
+ "main": "lib/index.js",
+ "maintainers": [
+ {
+ "name": "hueniverse",
+ "email": "eran@hueniverse.com"
+ }
+ ],
+ "name": "hawk",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/hueniverse/hawk.git"
+ },
+ "scripts": {
+ "test": "lab -a code -t 100 -L",
+ "test-cov-html": "lab -a code -r html -o coverage.html"
+ },
+ "version": "3.1.0"
+}
diff --git a/node_modules/request/node_modules/hawk/test/browser.js b/node_modules/request/node_modules/hawk/test/browser.js
new file mode 100755
index 000000000..49dc4cadd
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/browser.js
@@ -0,0 +1,1459 @@
+// Load modules
+
+var Url = require('url');
+var Code = require('code');
+var Hawk = require('../lib');
+var Hoek = require('hoek');
+var Lab = require('lab');
+var Browser = require('../lib/browser');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Browser', function () {
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ it('should generate a bewit then successfully authenticate it', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2',
+ host: 'example.com',
+ port: 80
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var bewit = Browser.client.bewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100, ext: 'some-app-data' });
+ req.url += '&bewit=' + bewit;
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(attributes.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('should generate a bewit then successfully authenticate it (no ext)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2',
+ host: 'example.com',
+ port: 80
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var bewit = Browser.client.bewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100 });
+ req.url += '&bewit=' + bewit;
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+ });
+
+ describe('bewit()', function () {
+
+ it('returns a valid bewit value', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdca3NjeHdOUjJ0SnBQMVQxekRMTlBiQjVVaUtJVTl0T1NKWFRVZEc3WDloOD1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('returns a valid bewit value (explicit HTTP port)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('http://example.com:8080/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdcaFpiSjNQMmNLRW80a3kwQzhqa1pBa1J5Q1p1ZWc0V1NOYnhWN3ZxM3hIVT1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('returns a valid bewit value (explicit HTTPS port)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com:8043/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdcL2t4UjhwK0xSaTdvQTRnUXc3cWlxa3BiVHRKYkR4OEtRMC9HRUwvVytTUT1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('returns a valid bewit value (null ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: null });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdcSUdZbUxnSXFMckNlOEN4dktQczRKbFdJQStValdKSm91d2dBUmlWaENBZz1c');
+ done();
+ });
+
+ it('errors on invalid options', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', 4);
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit(5, { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var credentials = {
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var bewit = Browser.client.bewit('https://example.com/somewhere/over/the/rainbow');
+ expect(bewit).to.equal('');
+ done();
+ });
+ });
+
+ it('generates a header then successfully parse it (configuration)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (node request)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Browser.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (browserify)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ getHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Browser.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (time offset)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', localtimeOffsetMsec: 100000 }).field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 100000 }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (no server header options)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (no server header)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header with stale ts and successfully authenticate on second call', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ Browser.utils.setNtpOffset(60 * 60 * 1000);
+ var header = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
+ req.authorization = header.field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Stale timestamp');
+
+ var res = {
+ headers: {
+ 'www-authenticate': err.output.headers['WWW-Authenticate']
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(Browser.utils.getNtpOffset()).to.equal(60 * 60 * 1000);
+ expect(Browser.client.authenticate(res, credentials, header.artifacts)).to.equal(true);
+ expect(Browser.utils.getNtpOffset()).to.equal(0);
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+ });
+
+ it('generates a header with stale ts and successfully authenticate on second call (manual localStorage)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var localStorage = new Browser.internals.LocalStorage();
+
+ Browser.utils.setStorage(localStorage);
+
+ Browser.utils.setNtpOffset(60 * 60 * 1000);
+ var header = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
+ req.authorization = header.field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Stale timestamp');
+
+ var res = {
+ headers: {
+ 'www-authenticate': err.output.headers['WWW-Authenticate']
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(parseInt(localStorage.getItem('hawk_ntp_offset'))).to.equal(60 * 60 * 1000);
+ expect(Browser.utils.getNtpOffset()).to.equal(60 * 60 * 1000);
+ expect(Browser.client.authenticate(res, credentials, header.artifacts)).to.equal(true);
+ expect(Browser.utils.getNtpOffset()).to.equal(0);
+ expect(parseInt(localStorage.getItem('hawk_ntp_offset'))).to.equal(0);
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+ });
+
+ it('generates a header then fails to parse it (missing server header hash)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Browser.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(false);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (with hash)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it then validate payload', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts)).to.be.true();
+ expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts)).to.be.false();
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (app)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(artifacts.app).to.equal('asd23ased');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (app, dlg)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(artifacts.app).to.equal('asd23ased');
+ expect(artifacts.dlg).to.equal('23434szr3q4d');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then fail authentication due to bad hash', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad payload hash');
+ done();
+ });
+ });
+ });
+
+ it('generates a header for one resource then fail to authenticate another', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Browser.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ req.url = '/something/else';
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(credentials).to.exist();
+ done();
+ });
+ });
+ });
+
+ describe('client', function () {
+
+ describe('header()', function () {
+
+ it('returns a valid authorization header (sha1)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var header = Browser.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="');
+ done();
+ });
+
+ it('returns a valid authorization header (sha256)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
+ done();
+ });
+
+ it('returns a valid authorization header (empty payload)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var header = Browser.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: '' }).field;
+ expect(header).to.equal('Hawk id=\"123456\", ts=\"1353809207\", nonce=\"Ygvqdz\", hash=\"404ghL7K+hfyhByKKejFBRGgTjU=\", ext=\"Bazinga!\", mac=\"Bh1sj1DOfFRWOdi3ww52nLCJdBE=\"');
+ done();
+ });
+
+ it('returns a valid authorization header (no ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('returns a valid authorization header (null ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain', ext: null }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('returns a valid authorization header (uri object)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var uri = Browser.utils.parseUri('https://example.net/somewhere/over/the/rainbow');
+ var header = Browser.client.header(uri, 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST');
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on empty uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on invalid uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header(4, 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on missing method', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', '', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on invalid method', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 5, { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credentials object');
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var credentials = {
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credentials object');
+ done();
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha256'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credentials object');
+ done();
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Unknown algorithm');
+ done();
+ });
+
+ it('uses a pre-calculated payload hash', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var options = { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' };
+ options.hash = Browser.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', options).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
+ done();
+ });
+ });
+
+ describe('authenticate()', function () {
+
+ it('skips tsm validation when missing ts', function (done) {
+
+ var res = {
+ headers: {
+ 'www-authenticate': 'Hawk error="Stale timestamp"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ ts: 1402135580,
+ nonce: 'iBRB6t',
+ method: 'GET',
+ resource: '/resource/4?filter=a',
+ host: 'example.com',
+ port: '8080',
+ ext: 'some-app-data'
+ };
+
+ expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+
+ it('returns false on invalid header', function (done) {
+
+ var res = {
+ headers: {
+ 'server-authorization': 'Hawk mac="abc", bad="xyz"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(Browser.client.authenticate(res, {})).to.equal(false);
+ done();
+ });
+
+ it('returns false on invalid mac', function (done) {
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain',
+ 'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1362336900',
+ nonce: 'eb5S_L',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ app: undefined,
+ dlg: undefined,
+ mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+ id: '123456'
+ };
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(false);
+ done();
+ });
+
+ it('returns true on ignoring hash', function (done) {
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain',
+ 'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1362336900',
+ nonce: 'eb5S_L',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ app: undefined,
+ dlg: undefined,
+ mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+ id: '123456'
+ };
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+
+ it('errors on invalid WWW-Authenticate header format', function (done) {
+
+ var res = {
+ headers: {
+ 'www-authenticate': 'Hawk ts="1362346425875", tsm="PhwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", x="Stale timestamp"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(Browser.client.authenticate(res, {})).to.equal(false);
+ done();
+ });
+
+ it('errors on invalid WWW-Authenticate header format', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var res = {
+ headers: {
+ 'www-authenticate': 'Hawk ts="1362346425875", tsm="hwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", error="Stale timestamp"'
+ },
+ getResponseHeader: function (header) {
+
+ return res.headers[header.toLowerCase()];
+ }
+ };
+
+ expect(Browser.client.authenticate(res, credentials)).to.equal(false);
+ done();
+ });
+ });
+
+ describe('message()', function () {
+
+ it('generates an authorization then successfully parse it', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+ });
+
+ it('generates an authorization using custom nonce/timestamp', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: credentials, nonce: 'abc123', timestamp: 1398536270957 });
+ expect(auth).to.exist();
+ expect(auth.nonce).to.equal('abc123');
+ expect(auth.ts).to.equal(1398536270957);
+ done();
+ });
+ });
+
+ it('errors on missing host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message(null, 8080, 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on invalid host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message(5, 8080, 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on missing port', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 0, 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on invalid port', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 'a', 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on missing message', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 8080, undefined, { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on null message', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 8080, null, { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on invalid message', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Browser.client.message('example.com', 8080, 5, { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var auth = Browser.client.message('example.com', 8080, 'some message', {});
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var auth = Browser.client.message('example.com', 8080, 'some message');
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var creds = Hoek.clone(credentials);
+ delete creds.id;
+ var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var creds = Hoek.clone(credentials);
+ delete creds.key;
+ var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var creds = Hoek.clone(credentials);
+ creds.algorithm = 'blah';
+ var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+ });
+
+ describe('authenticateTimestamp()', function (done) {
+
+ it('validates a timestamp', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var tsm = Hawk.crypto.timestampMessage(credentials);
+ expect(Browser.client.authenticateTimestamp(tsm, credentials)).to.equal(true);
+ done();
+ });
+ });
+
+ it('validates a timestamp without updating local time', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var offset = Browser.utils.getNtpOffset();
+ var tsm = Hawk.crypto.timestampMessage(credentials, 10000);
+ expect(Browser.client.authenticateTimestamp(tsm, credentials, false)).to.equal(true);
+ expect(offset).to.equal(Browser.utils.getNtpOffset());
+ done();
+ });
+ });
+
+ it('detects a bad timestamp', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var tsm = Hawk.crypto.timestampMessage(credentials);
+ tsm.ts = 4;
+ expect(Browser.client.authenticateTimestamp(tsm, credentials)).to.equal(false);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('internals', function () {
+
+ describe('LocalStorage', function () {
+
+ it('goes through the full lifecycle', function (done) {
+
+ var storage = new Browser.internals.LocalStorage();
+ expect(storage.length).to.equal(0);
+ expect(storage.getItem('a')).to.equal(null);
+ storage.setItem('a', 5);
+ expect(storage.length).to.equal(1);
+ expect(storage.key()).to.equal('a');
+ expect(storage.key(0)).to.equal('a');
+ expect(storage.getItem('a')).to.equal('5');
+ storage.setItem('b', 'test');
+ expect(storage.key()).to.equal('a');
+ expect(storage.key(0)).to.equal('a');
+ expect(storage.key(1)).to.equal('b');
+ expect(storage.length).to.equal(2);
+ expect(storage.getItem('b')).to.equal('test');
+ storage.removeItem('a');
+ expect(storage.length).to.equal(1);
+ expect(storage.getItem('a')).to.equal(null);
+ expect(storage.getItem('b')).to.equal('test');
+ storage.clear();
+ expect(storage.length).to.equal(0);
+ expect(storage.getItem('a')).to.equal(null);
+ expect(storage.getItem('b')).to.equal(null);
+ done();
+ });
+ });
+ });
+
+ describe('utils', function () {
+
+ describe('setStorage()', function () {
+
+ it('sets storage for the first time', function (done) {
+
+ Browser.utils.storage = new Browser.internals.LocalStorage(); // Reset state
+
+ expect(Browser.utils.storage.getItem('hawk_ntp_offset')).to.not.exist();
+ Browser.utils.storage.setItem('test', '1');
+ Browser.utils.setStorage(new Browser.internals.LocalStorage());
+ expect(Browser.utils.storage.getItem('test')).to.not.exist();
+ Browser.utils.storage.setItem('test', '2');
+ expect(Browser.utils.storage.getItem('test')).to.equal('2');
+ done();
+ });
+ });
+
+ describe('setNtpOffset()', function (done) {
+
+ it('catches localStorage errors', { parallel: false }, function (done) {
+
+ var orig = Browser.utils.storage.setItem;
+ var consoleOrig = console.error;
+ var count = 0;
+ console.error = function () {
+
+ if (count++ === 2) {
+
+ console.error = consoleOrig;
+ }
+ };
+
+ Browser.utils.storage.setItem = function () {
+
+ Browser.utils.storage.setItem = orig;
+ throw new Error();
+ };
+
+ expect(function () {
+
+ Browser.utils.setNtpOffset(100);
+ }).not.to.throw();
+
+ done();
+ });
+ });
+
+ describe('parseAuthorizationHeader()', function (done) {
+
+ it('returns null on missing header', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader()).to.equal(null);
+ done();
+ });
+
+ it('returns null on bad header syntax (structure)', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader('Hawk')).to.equal(null);
+ done();
+ });
+
+ it('returns null on bad header syntax (parts)', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader(' ')).to.equal(null);
+ done();
+ });
+
+ it('returns null on bad scheme name', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader('Basic asdasd')).to.equal(null);
+ done();
+ });
+
+ it('returns null on bad attribute value', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader('Hawk test="\t"', ['test'])).to.equal(null);
+ done();
+ });
+
+ it('returns null on duplicated attribute', function (done) {
+
+ expect(Browser.utils.parseAuthorizationHeader('Hawk test="a", test="b"', ['test'])).to.equal(null);
+ done();
+ });
+ });
+
+ describe('parseUri()', function () {
+
+ it('returns empty port when unknown scheme', function (done) {
+
+ var uri = Browser.utils.parseUri('ftp://domain');
+ expect(uri.port).to.equal('');
+ done();
+ });
+
+ it('returns default port when missing', function (done) {
+
+ var uri = Browser.utils.parseUri('http://');
+ expect(uri.port).to.equal('80');
+ done();
+ });
+ });
+
+ var str = 'https://www.google.ca/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=url';
+ var base64str = 'aHR0cHM6Ly93d3cuZ29vZ2xlLmNhL3dlYmhwP3NvdXJjZWlkPWNocm9tZS1pbnN0YW50Jmlvbj0xJmVzcHY9MiZpZT1VVEYtOCNxPXVybA';
+
+ describe('base64urlEncode()', function () {
+
+ it('should base64 URL-safe decode a string', function (done) {
+
+ expect(Browser.utils.base64urlEncode(str)).to.equal(base64str);
+ done();
+ });
+ });
+ });
+});
diff --git a/node_modules/request/node_modules/hawk/test/client.js b/node_modules/request/node_modules/hawk/test/client.js
new file mode 100755
index 000000000..d6be231ae
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/client.js
@@ -0,0 +1,440 @@
+// Load modules
+
+var Url = require('url');
+var Code = require('code');
+var Hawk = require('../lib');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Client', function () {
+
+ describe('header()', function () {
+
+ it('returns a valid authorization header (sha1)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var header = Hawk.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="');
+ done();
+ });
+
+ it('returns a valid authorization header (sha256)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
+ done();
+ });
+
+ it('returns a valid authorization header (no ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('returns a valid authorization header (null ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain', ext: null }).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('returns a valid authorization header (empty payload)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: '', contentType: 'text/plain' }).field;
+ expect(header).to.equal('Hawk id=\"123456\", ts=\"1353809207\", nonce=\"Ygvqdz\", hash=\"q/t+NNAkQZNlq/aAD6PlexImwQTxwgT2MahfTa9XRLA=\", mac=\"U5k16YEzn3UnBHKeBzsDXn067Gu3R4YaY6xOt9PYRZM=\"');
+ done();
+ });
+
+ it('returns a valid authorization header (pre hashed payload)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var options = { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' };
+ options.hash = Hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', options).field;
+ expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
+ done();
+ });
+
+ it('errors on missing uri', function (done) {
+
+ var header = Hawk.client.header('', 'POST');
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on invalid uri', function (done) {
+
+ var header = Hawk.client.header(4, 'POST');
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on missing method', function (done) {
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', '');
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on invalid method', function (done) {
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 5);
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST');
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid argument type');
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var credentials = {
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credential object');
+ done();
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credential object');
+ done();
+ });
+
+ it('errors on invalid credentials', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha256'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Invalid credential object');
+ done();
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 });
+ expect(header.field).to.equal('');
+ expect(header.err).to.equal('Unknown algorithm');
+ done();
+ });
+ });
+
+ describe('authenticate()', function () {
+
+ it('returns false on invalid header', function (done) {
+
+ var res = {
+ headers: {
+ 'server-authorization': 'Hawk mac="abc", bad="xyz"'
+ }
+ };
+
+ expect(Hawk.client.authenticate(res, {})).to.equal(false);
+ done();
+ });
+
+ it('returns false on invalid mac', function (done) {
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain',
+ 'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+ }
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1362336900',
+ nonce: 'eb5S_L',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ app: undefined,
+ dlg: undefined,
+ mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+ id: '123456'
+ };
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(false);
+ done();
+ });
+
+ it('returns true on ignoring hash', function (done) {
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain',
+ 'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"'
+ }
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1362336900',
+ nonce: 'eb5S_L',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ app: undefined,
+ dlg: undefined,
+ mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=',
+ id: '123456'
+ };
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+
+ it('fails on invalid WWW-Authenticate header format', function (done) {
+
+ var header = 'Hawk ts="1362346425875", tsm="PhwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", x="Stale timestamp"';
+ expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, {})).to.equal(false);
+ done();
+ });
+
+ it('fails on invalid WWW-Authenticate header format', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var header = 'Hawk ts="1362346425875", tsm="hwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", error="Stale timestamp"';
+ expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, credentials)).to.equal(false);
+ done();
+ });
+
+ it('skips tsm validation when missing ts', function (done) {
+
+ var header = 'Hawk error="Stale timestamp"';
+ expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, {})).to.equal(true);
+ done();
+ });
+ });
+
+ describe('message()', function () {
+
+ it('generates authorization', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.exist();
+ expect(auth.ts).to.equal(1353809207);
+ expect(auth.nonce).to.equal('abc123');
+ done();
+ });
+
+ it('errors on invalid host', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message(5, 80, 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on invalid port', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', '80', 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on missing host', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 0, 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on null message', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, null, { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on missing message', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, undefined, { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on invalid message', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, 5, { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, 'I am the boodyman');
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var credentials = {
+ key: '2983d45yun89q',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha1'
+ };
+
+ var auth = Hawk.client.message('example.com', 80, 'I am the boodyman', { credentials: credentials, timestamp: 1353809207, nonce: 'abc123' });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+});
diff --git a/node_modules/request/node_modules/hawk/test/crypto.js b/node_modules/request/node_modules/hawk/test/crypto.js
new file mode 100755
index 000000000..1131628bf
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/crypto.js
@@ -0,0 +1,70 @@
+// Load modules
+
+var Code = require('code');
+var Hawk = require('../lib');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Crypto', function () {
+
+ describe('generateNormalizedString()', function () {
+
+ it('should return a valid normalized string', function (done) {
+
+ expect(Hawk.crypto.generateNormalizedString('header', {
+ ts: 1357747017,
+ nonce: 'k3k4j5',
+ method: 'GET',
+ resource: '/resource/something',
+ host: 'example.com',
+ port: 8080
+ })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\n\n');
+
+ done();
+ });
+
+ it('should return a valid normalized string (ext)', function (done) {
+
+ expect(Hawk.crypto.generateNormalizedString('header', {
+ ts: 1357747017,
+ nonce: 'k3k4j5',
+ method: 'GET',
+ resource: '/resource/something',
+ host: 'example.com',
+ port: 8080,
+ ext: 'this is some app data'
+ })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\nthis is some app data\n');
+
+ done();
+ });
+
+ it('should return a valid normalized string (payload + ext)', function (done) {
+
+ expect(Hawk.crypto.generateNormalizedString('header', {
+ ts: 1357747017,
+ nonce: 'k3k4j5',
+ method: 'GET',
+ resource: '/resource/something',
+ host: 'example.com',
+ port: 8080,
+ hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=',
+ ext: 'this is some app data'
+ })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\nU4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=\nthis is some app data\n');
+
+ done();
+ });
+ });
+});
diff --git a/node_modules/request/node_modules/hawk/test/index.js b/node_modules/request/node_modules/hawk/test/index.js
new file mode 100755
index 000000000..39f2c5b86
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/index.js
@@ -0,0 +1,378 @@
+// Load modules
+
+var Url = require('url');
+var Code = require('code');
+var Hawk = require('../lib');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Hawk', function () {
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ it('generates a header then successfully parse it (configuration)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header(Url.parse('http://example.com:8080/resource/4?filter=a'), req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ expect(req.authorization).to.exist();
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (node request)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (absolute request uri)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: 'http://example.com:8080/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (no server header options)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then fails to parse it (missing server header hash)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:8080',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ var payload = 'some not so random text';
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
+ req.headers.authorization = reqHeader.field;
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload(payload, credentials, artifacts, req.headers['content-type'])).to.equal(true);
+
+ var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ };
+
+ res.headers['server-authorization'] = Hawk.server.header(credentials, artifacts);
+ expect(res.headers['server-authorization']).to.exist();
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts, { payload: 'some reply' })).to.equal(false);
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (with hash)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it then validate payload', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts)).to.be.true();
+ expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts)).to.be.false();
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parses and validates payload', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, { payload: 'hola!' }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (app)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(artifacts.app).to.equal('asd23ased');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then successfully parse it (app, dlg)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(artifacts.ext).to.equal('some-app-data');
+ expect(artifacts.app).to.equal('asd23ased');
+ expect(artifacts.dlg).to.equal('23434szr3q4d');
+ done();
+ });
+ });
+ });
+
+ it('generates a header then fail authentication due to bad hash', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
+ Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad payload hash');
+ done();
+ });
+ });
+ });
+
+ it('generates a header for one resource then fail to authenticate another', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
+ req.url = '/something/else';
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(credentials).to.exist();
+ done();
+ });
+ });
+ });
+});
diff --git a/node_modules/request/node_modules/hawk/test/readme.js b/node_modules/request/node_modules/hawk/test/readme.js
new file mode 100755
index 000000000..a46626466
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/readme.js
@@ -0,0 +1,95 @@
+// Load modules
+
+var Code = require('code');
+var Hawk = require('../lib');
+var Hoek = require('hoek');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('README', function () {
+
+ describe('core', function () {
+
+ var credentials = {
+ id: 'dh37fgj492je',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+ };
+
+ var options = {
+ credentials: credentials,
+ timestamp: 1353832234,
+ nonce: 'j4h3g2',
+ ext: 'some-app-ext-data'
+ };
+
+ it('should generate a header protocol example', function (done) {
+
+ var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', options).field;
+
+ expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="');
+ done();
+ });
+
+ it('should generate a normalized string protocol example', function (done) {
+
+ var normalized = Hawk.crypto.generateNormalizedString('header', {
+ credentials: credentials,
+ ts: options.timestamp,
+ nonce: options.nonce,
+ method: 'GET',
+ resource: '/resource?a=1&b=2',
+ host: 'example.com',
+ port: 8000,
+ ext: options.ext
+ });
+
+ expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nGET\n/resource?a=1&b=2\nexample.com\n8000\n\nsome-app-ext-data\n');
+ done();
+ });
+
+ var payloadOptions = Hoek.clone(options);
+ payloadOptions.payload = 'Thank you for flying Hawk';
+ payloadOptions.contentType = 'text/plain';
+
+ it('should generate a header protocol example (with payload)', function (done) {
+
+ var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'POST', payloadOptions).field;
+
+ expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="');
+ done();
+ });
+
+ it('should generate a normalized string protocol example (with payload)', function (done) {
+
+ var normalized = Hawk.crypto.generateNormalizedString('header', {
+ credentials: credentials,
+ ts: options.timestamp,
+ nonce: options.nonce,
+ method: 'POST',
+ resource: '/resource?a=1&b=2',
+ host: 'example.com',
+ port: 8000,
+ hash: Hawk.crypto.calculatePayloadHash(payloadOptions.payload, credentials.algorithm, payloadOptions.contentType),
+ ext: options.ext
+ });
+
+ expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource?a=1&b=2\nexample.com\n8000\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\nsome-app-ext-data\n');
+ done();
+ });
+ });
+});
+
diff --git a/node_modules/request/node_modules/hawk/test/server.js b/node_modules/request/node_modules/hawk/test/server.js
new file mode 100755
index 000000000..b95b7cd02
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/server.js
@@ -0,0 +1,1314 @@
+// Load modules
+
+var Url = require('url');
+var Code = require('code');
+var Hawk = require('../lib');
+var Hoek = require('hoek');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Server', function () {
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ describe('authenticate()', function () {
+
+ it('parses a valid authentication header (sha1)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+
+ it('parses a valid authentication header (sha256)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/1?b=1&a=2',
+ host: 'example.com',
+ port: 8000,
+ authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+
+ it('parses a valid authentication header (host override)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example1.com:8080',
+ authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { host: 'example.com', localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+
+ it('parses a valid authentication header (host port override)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example1.com:80',
+ authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"'
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { host: 'example.com', port: 8080, localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+
+ it('parses a valid authentication header (POST with payload)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123456", ts="1357926341", nonce="1AwuJD", hash="qAiXIVv+yjDATneWxZP2YCTa9aHRgQdnH9b3Wc+o3dg=", ext="some-app-data", mac="UeYcj5UoTVaAWXNvJfLVia7kU3VabxCqrccXP8sUGC4="'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1357926341000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+
+ it('errors on missing hash', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/1?b=1&a=2',
+ host: 'example.com',
+ port: 8000,
+ authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { payload: 'body', localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing required payload hash');
+ done();
+ });
+ });
+
+ it('errors on a stale timestamp', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123456", ts="1362337299", nonce="UzmxSs", ext="some-app-data", mac="wnNUxchvvryMH2RxckTdZ/gY3ijzvccx4keVvELC61w="'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Stale timestamp');
+ var header = err.output.headers['WWW-Authenticate'];
+ var ts = header.match(/^Hawk ts\=\"(\d+)\"\, tsm\=\"([^\"]+)\"\, error=\"Stale timestamp\"$/);
+ var now = Hawk.utils.now();
+ expect(parseInt(ts[1], 10) * 1000).to.be.within(now - 1000, now + 1000);
+
+ var res = {
+ headers: {
+ 'www-authenticate': header
+ }
+ };
+
+ expect(Hawk.client.authenticate(res, credentials, artifacts)).to.equal(true);
+ done();
+ });
+ });
+
+ it('errors on a replay', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="bXx7a7p1h9QYQNZ8x7QhvDQym8ACgab4m3lVSFn4DBw=", ext="hello"'
+ };
+
+ var memoryCache = {};
+ var options = {
+ localtimeOffsetMsec: 1353788437000 - Hawk.utils.now(),
+ nonceFunc: function (key, nonce, ts, callback) {
+
+ if (memoryCache[key + nonce]) {
+ return callback(new Error());
+ }
+
+ memoryCache[key + nonce] = true;
+ return callback();
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+
+ Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid nonce');
+ done();
+ });
+ });
+ });
+
+ it('does not error on nonce collision if keys differ', function (done) {
+
+ var reqSteve = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="bXx7a7p1h9QYQNZ8x7QhvDQym8ACgab4m3lVSFn4DBw=", ext="hello"'
+ };
+
+ var reqBob = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="456", ts="1353788437", nonce="k3j4h2", mac="LXfmTnRzrLd9TD7yfH+4se46Bx6AHyhpM94hLCiNia4=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ '123': {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ },
+ '456': {
+ id: id,
+ key: 'xrunpaw3489ruxnpa98w4rxnwerxhqb98rpaxn39848',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'bob'
+ }
+ };
+
+ return callback(null, credentials[id]);
+ };
+
+ var memoryCache = {};
+ var options = {
+ localtimeOffsetMsec: 1353788437000 - Hawk.utils.now(),
+ nonceFunc: function (key, nonce, ts, callback) {
+
+ if (memoryCache[key + nonce]) {
+ return callback(new Error());
+ }
+
+ memoryCache[key + nonce] = true;
+ return callback();
+ }
+ };
+
+ Hawk.server.authenticate(reqSteve, credentialsFunc, options, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+
+ Hawk.server.authenticate(reqBob, credentialsFunc, options, function (err, credentials, artifacts) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('bob');
+ done();
+ });
+ });
+ });
+
+ it('errors on an invalid authentication header: wrong scheme', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Basic asdasdasdasd'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.not.exist();
+ done();
+ });
+ });
+
+ it('errors on an invalid authentication header: no scheme', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: '!@#'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid header syntax');
+ done();
+ });
+ });
+
+ it('errors on an missing authorization header', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.isMissing).to.equal(true);
+ done();
+ });
+ });
+
+ it('errors on an missing host header', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ headers: {
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid Host header');
+ done();
+ });
+ });
+
+ it('errors on an missing authorization attribute (id)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing attributes');
+ done();
+ });
+ });
+
+ it('errors on an missing authorization attribute (ts)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing attributes');
+ done();
+ });
+ });
+
+ it('errors on an missing authorization attribute (nonce)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing attributes');
+ done();
+ });
+ });
+
+ it('errors on an missing authorization attribute (mac)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing attributes');
+ done();
+ });
+ });
+
+ it('errors on an unknown authorization attribute', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", x="3", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Unknown attribute: x');
+ done();
+ });
+ });
+
+ it('errors on an bad authorization header format', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123\\", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad header format');
+ done();
+ });
+ });
+
+ it('errors on an bad authorization attribute value', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="\t", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad attribute value: id');
+ done();
+ });
+ });
+
+ it('errors on an empty authorization attribute value', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad attribute value: id');
+ done();
+ });
+ });
+
+ it('errors on duplicated authorization attribute key', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", id="456", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Duplicate attribute: id');
+ done();
+ });
+ });
+
+ it('errors on an invalid authorization header format', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk'
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid header syntax');
+ done();
+ });
+ });
+
+ it('errors on an bad host header (missing host)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: ':8080',
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid Host header');
+ done();
+ });
+ });
+
+ it('errors on an bad host header (pad port)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com:something',
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ }
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid Host header');
+ done();
+ });
+ });
+
+ it('errors on credentialsFunc error', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ return callback(new Error('Unknown user'));
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown user');
+ done();
+ });
+ });
+
+ it('errors on credentialsFunc error (with credentials)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ return callback(new Error('Unknown user'), { some: 'value' });
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown user');
+ expect(credentials.some).to.equal('value');
+ done();
+ });
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ return callback(null, null);
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Unknown credentials');
+ done();
+ });
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid credentials');
+ expect(err.output.payload.message).to.equal('An internal server error occurred');
+ done();
+ });
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: '23434d3q4d5345d',
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid credentials');
+ expect(err.output.payload.message).to.equal('An internal server error occurred');
+ done();
+ });
+ });
+
+ it('errors on unknown credentials algorithm', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'hmac-sha-0',
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown algorithm');
+ expect(err.output.payload.message).to.equal('An internal server error occurred');
+ done();
+ });
+ });
+
+ it('errors on unknown bad mac', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcU4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
+ };
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad mac');
+ done();
+ });
+ });
+ });
+
+ describe('header()', function () {
+
+ it('generates header', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('Hawk mac=\"n14wVJK4cOxAytPUMc5bPezQzuJGl5n7MYXhFQgEKsE=\", hash=\"f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=\", ext=\"response-specific\"');
+ done();
+ });
+
+ it('generates header (empty payload)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: '', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('Hawk mac=\"i8/kUBDx0QF+PpCtW860kkV/fa9dbwEoe/FpGUXowf0=\", hash=\"q/t+NNAkQZNlq/aAD6PlexImwQTxwgT2MahfTa9XRLA=\", ext=\"response-specific\"');
+ done();
+ });
+
+ it('generates header (pre calculated hash)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var options = { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' };
+ options.hash = Hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+ var header = Hawk.server.header(credentials, artifacts, options);
+ expect(header).to.equal('Hawk mac=\"n14wVJK4cOxAytPUMc5bPezQzuJGl5n7MYXhFQgEKsE=\", hash=\"f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=\", ext=\"response-specific\"');
+ done();
+ });
+
+ it('generates header (null ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: null });
+ expect(header).to.equal('Hawk mac=\"6PrybJTJs20jsgBw5eilXpcytD8kUbaIKNYXL+6g0ns=\", hash=\"f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=\"');
+ done();
+ });
+
+ it('errors on missing artifacts', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var header = Hawk.server.header(credentials, null, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('');
+ done();
+ });
+
+ it('errors on invalid artifacts', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var header = Hawk.server.header(credentials, 5, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('');
+ done();
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(null, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('');
+ done();
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('');
+ done();
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'x',
+ user: 'steve'
+ };
+
+ var artifacts = {
+ method: 'POST',
+ host: 'example.com',
+ port: '8080',
+ resource: '/resource/4?filter=a',
+ ts: '1398546787',
+ nonce: 'xUwusx',
+ hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=',
+ ext: 'some-app-data',
+ mac: 'dvIvMThwi28J61Jc3P0ryAhuKpanU63GXdx6hkmQkJA=',
+ id: '123456'
+ };
+
+ var header = Hawk.server.header(credentials, artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
+ expect(header).to.equal('');
+ done();
+ });
+ });
+
+ describe('authenticateMessage()', function () {
+
+ it('errors on invalid authorization (ts)', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ delete auth.ts;
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid authorization');
+ done();
+ });
+ });
+ });
+
+ it('errors on invalid authorization (nonce)', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ delete auth.nonce;
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid authorization');
+ done();
+ });
+ });
+ });
+
+ it('errors on invalid authorization (hash)', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ delete auth.hash;
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid authorization');
+ done();
+ });
+ });
+ });
+
+ it('errors with credentials', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, function (id, callback) {
+
+ callback(new Error('something'), { some: 'value' });
+ }, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('something');
+ expect(credentials.some).to.equal('value');
+ done();
+ });
+ });
+ });
+
+ it('errors on nonce collision', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {
+ nonceFunc: function (key, nonce, ts, nonceCallback) {
+
+ nonceCallback(true);
+ }
+ }, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid nonce');
+ done();
+ });
+ });
+ });
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ it('should generate an authorization then successfully parse it', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on mismatching host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example1.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Bad mac');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on stale timestamp', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { localtimeOffsetMsec: 100000 }, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Stale timestamp');
+ done();
+ });
+ });
+ });
+
+ it('overrides timestampSkewSec', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials, localtimeOffsetMsec: 100000 });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { timestampSkewSec: 500 }, function (err, credentials) {
+
+ expect(err).to.not.exist();
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid authorization', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+ delete auth.id;
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid authorization');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on bad hash', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message1', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Bad message hash');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on nonce error', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {
+ nonceFunc: function (key, nonce, ts, callback) {
+
+ callback(new Error('kaboom'));
+ }
+ }, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid nonce');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on credentials error', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(new Error('kablooey'));
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('kablooey');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on missing credentials', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback();
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown credentials');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid credentials', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(null, {});
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid credentials');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid credentials algorithm', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(null, { key: '123', algorithm: '456' });
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown algorithm');
+ done();
+ });
+ });
+ });
+
+ it('should fail on missing host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message(null, 8080, 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('should fail on missing credentials', function (done) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', {});
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('should fail on invalid algorithm', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var creds = Hoek.clone(credentials);
+ creds.algorithm = 'blah';
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: creds });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+ });
+
+ describe('authenticatePayloadHash()', function () {
+
+ it('checks payload hash', function (done) {
+
+ expect(Hawk.server.authenticatePayloadHash('abcdefg', { hash: 'abcdefg' })).to.equal(true);
+ expect(Hawk.server.authenticatePayloadHash('1234567', { hash: 'abcdefg' })).to.equal(false);
+ done();
+ });
+ });
+});
+
diff --git a/node_modules/request/node_modules/hawk/test/uri.js b/node_modules/request/node_modules/hawk/test/uri.js
new file mode 100755
index 000000000..1b623c091
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/uri.js
@@ -0,0 +1,849 @@
+// Load modules
+
+var Http = require('http');
+var Url = require('url');
+var Code = require('code');
+var Hawk = require('../lib');
+var Hoek = require('hoek');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Uri', function () {
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ it('should generate a bewit then successfully authenticate it', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2',
+ host: 'example.com',
+ port: 80
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100, ext: 'some-app-data' });
+ req.url += '&bewit=' + bewit;
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(attributes.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+ });
+
+ it('should generate a bewit then successfully authenticate it (no ext)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2',
+ host: 'example.com',
+ port: 80
+ };
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100 });
+ req.url += '&bewit=' + bewit;
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+ });
+
+ it('should successfully authenticate a request (last param)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(attributes.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+
+ it('should successfully authenticate a request (first param)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ&a=1&b=2',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(attributes.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+
+ it('should successfully authenticate a request (only param)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ expect(attributes.ext).to.equal('some-app-data');
+ done();
+ });
+ });
+
+ it('should fail on multiple authentication', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080,
+ authorization: 'Basic asdasdasdasd'
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Multiple authentications');
+ done();
+ });
+ });
+
+ it('should fail on method other than GET', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ host: 'example.com',
+ port: 8080
+ };
+
+ var exp = Math.floor(Hawk.utils.now() / 1000) + 60;
+ var ext = 'some-app-data';
+ var mac = Hawk.crypto.calculateMac('bewit', credentials, {
+ timestamp: exp,
+ nonce: '',
+ method: req.method,
+ resource: req.url,
+ host: req.host,
+ port: req.port,
+ ext: ext
+ });
+
+ var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + ext;
+
+ req.url += '&bewit=' + Hoek.base64urlEncode(bewit);
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid method');
+ done();
+ });
+ });
+ });
+
+ it('should fail on invalid host header', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ headers: {
+ host: 'example.com:something'
+ }
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid Host header');
+ done();
+ });
+ });
+
+ it('should fail on empty bewit', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Empty bewit');
+ expect(err.isMissing).to.not.exist();
+ done();
+ });
+ });
+
+ it('should fail on invalid bewit', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=*',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid bewit encoding');
+ expect(err.isMissing).to.not.exist();
+ done();
+ });
+ });
+
+ it('should fail on missing bewit', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.not.exist();
+ expect(err.isMissing).to.equal(true);
+ done();
+ });
+ });
+
+ it('should fail on invalid bewit structure', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=abc',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Invalid bewit structure');
+ done();
+ });
+ });
+
+ it('should fail on empty bewit attribute', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=YVxcY1xk',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing bewit attributes');
+ done();
+ });
+ });
+
+ it('should fail on missing bewit id attribute', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=XDQ1NTIxNDc2MjJcK0JFbFhQMXhuWjcvd1Nrbm1ldGhlZm5vUTNHVjZNSlFVRHk4NWpTZVJ4VT1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Missing bewit attributes');
+ done();
+ });
+ });
+
+ it('should fail on expired access', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDEzNTY0MTg1ODNcWk1wZlMwWU5KNHV0WHpOMmRucTRydEk3NXNXTjFjeWVITTcrL0tNZFdVQT1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Access expired');
+ done();
+ });
+ });
+
+ it('should fail on credentials function error', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(Hawk.error.badRequest('Boom'));
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Boom');
+ done();
+ });
+ });
+
+ it('should fail on credentials function error with credentials', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(Hawk.error.badRequest('Boom'), { some: 'value' });
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Boom');
+ expect(credentials.some).to.equal('value');
+ done();
+ });
+ });
+
+ it('should fail on null credentials function response', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(null, null);
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Unknown credentials');
+ done();
+ });
+ });
+
+ it('should fail on invalid credentials function response', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(null, {});
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid credentials');
+ done();
+ });
+ });
+
+ it('should fail on invalid credentials function response (unknown algorithm)', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(null, { key: 'xxx', algorithm: 'xxx' });
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown algorithm');
+ done();
+ });
+ });
+
+ it('should fail on expired access', function (done) {
+
+ var req = {
+ method: 'GET',
+ url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ',
+ host: 'example.com',
+ port: 8080
+ };
+
+ Hawk.uri.authenticate(req, function (id, callback) {
+
+ callback(null, { key: 'xxx', algorithm: 'sha256' });
+ }, {}, function (err, credentials, attributes) {
+
+ expect(err).to.exist();
+ expect(err.output.payload.message).to.equal('Bad mac');
+ done();
+ });
+ });
+
+ describe('getBewit()', function () {
+
+ it('returns a valid bewit value', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdca3NjeHdOUjJ0SnBQMVQxekRMTlBiQjVVaUtJVTl0T1NKWFRVZEc3WDloOD1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('returns a valid bewit value (explicit port)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com:8080/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdcaFpiSjNQMmNLRW80a3kwQzhqa1pBa1J5Q1p1ZWc0V1NOYnhWN3ZxM3hIVT1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('returns a valid bewit value (null ext)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: null });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdcSUdZbUxnSXFMckNlOEN4dktQczRKbFdJQStValdKSm91d2dBUmlWaENBZz1c');
+ done();
+ });
+
+ it('returns a valid bewit value (parsed uri)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit(Url.parse('https://example.com/somewhere/over/the/rainbow'), { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdca3NjeHdOUjJ0SnBQMVQxekRMTlBiQjVVaUtJVTl0T1NKWFRVZEc3WDloOD1ceGFuZHlhbmR6');
+ done();
+ });
+
+ it('errors on invalid options', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', 4);
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid uri', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit(5, { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid credentials (id)', function (done) {
+
+ var credentials = {
+ key: '2983d45yun89q',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing credentials', function (done) {
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid credentials (key)', function (done) {
+
+ var credentials = {
+ id: '123456',
+ algorithm: 'sha256'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on invalid algorithm', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, ext: 'xandyandz' });
+ expect(bewit).to.equal('');
+ done();
+ });
+
+ it('errors on missing options', function (done) {
+
+ var credentials = {
+ id: '123456',
+ key: '2983d45yun89q',
+ algorithm: 'hmac-sha-0'
+ };
+
+ var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow');
+ expect(bewit).to.equal('');
+ done();
+ });
+ });
+ describe('authenticateMessage()', function () {
+
+ var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ id: id,
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: (id === '1' ? 'sha1' : 'sha256'),
+ user: 'steve'
+ };
+
+ return callback(null, credentials);
+ };
+
+ it('should generate an authorization then successfully parse it', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.not.exist();
+ expect(credentials.user).to.equal('steve');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on mismatching host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example1.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Bad mac');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on stale timestamp', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { localtimeOffsetMsec: 100000 }, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Stale timestamp');
+ done();
+ });
+ });
+ });
+
+ it('overrides timestampSkewSec', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials, localtimeOffsetMsec: 100000 });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, { timestampSkewSec: 500 }, function (err, credentials) {
+
+ expect(err).to.not.exist();
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid authorization', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+ delete auth.id;
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid authorization');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on bad hash', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message1', auth, credentialsFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Bad message hash');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on nonce error', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, credentialsFunc, {
+ nonceFunc: function (key, nonce, ts, callback) {
+
+ callback(new Error('kaboom'));
+ }
+ }, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid nonce');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on credentials error', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(new Error('kablooey'));
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('kablooey');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on missing credentials', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback();
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown credentials');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid credentials', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(null, {});
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Invalid credentials');
+ done();
+ });
+ });
+ });
+
+ it('should fail authorization on invalid credentials algorithm', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: credentials });
+ expect(auth).to.exist();
+
+ var errFunc = function (id, callback) {
+
+ callback(null, { key: '123', algorithm: '456' });
+ };
+
+ Hawk.server.authenticateMessage('example.com', 8080, 'some message', auth, errFunc, {}, function (err, credentials) {
+
+ expect(err).to.exist();
+ expect(err.message).to.equal('Unknown algorithm');
+ done();
+ });
+ });
+ });
+
+ it('should fail on missing host', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var auth = Hawk.client.message(null, 8080, 'some message', { credentials: credentials });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+
+ it('should fail on missing credentials', function (done) {
+
+ var auth = Hawk.client.message('example.com', 8080, 'some message', {});
+ expect(auth).to.not.exist();
+ done();
+ });
+
+ it('should fail on invalid algorithm', function (done) {
+
+ credentialsFunc('123456', function (err, credentials) {
+
+ var creds = Hoek.clone(credentials);
+ creds.algorithm = 'blah';
+ var auth = Hawk.client.message('example.com', 8080, 'some message', { credentials: creds });
+ expect(auth).to.not.exist();
+ done();
+ });
+ });
+ });
+});
+
diff --git a/node_modules/request/node_modules/hawk/test/utils.js b/node_modules/request/node_modules/hawk/test/utils.js
new file mode 100755
index 000000000..1bfef65f8
--- /dev/null
+++ b/node_modules/request/node_modules/hawk/test/utils.js
@@ -0,0 +1,121 @@
+// Load modules
+
+var Code = require('code');
+var Hawk = require('../lib');
+var Lab = require('lab');
+var Package = require('../package.json');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('Utils', function () {
+
+ describe('parseHost()', function () {
+
+ it('returns port 80 for non tls node request', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com',
+ 'content-type': 'text/plain;x=y'
+ }
+ };
+
+ expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(80);
+ done();
+ });
+
+ it('returns port 443 for non tls node request', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: 'example.com',
+ 'content-type': 'text/plain;x=y'
+ },
+ connection: {
+ encrypted: true
+ }
+ };
+
+ expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(443);
+ done();
+ });
+
+ it('returns port 443 for non tls node request (IPv6)', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: '[123:123:123]',
+ 'content-type': 'text/plain;x=y'
+ },
+ connection: {
+ encrypted: true
+ }
+ };
+
+ expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(443);
+ done();
+ });
+
+ it('parses IPv6 headers', function (done) {
+
+ var req = {
+ method: 'POST',
+ url: '/resource/4?filter=a',
+ headers: {
+ host: '[123:123:123]:8000',
+ 'content-type': 'text/plain;x=y'
+ },
+ connection: {
+ encrypted: true
+ }
+ };
+
+ var host = Hawk.utils.parseHost(req, 'Host');
+ expect(host.port).to.equal('8000');
+ expect(host.name).to.equal('[123:123:123]');
+ done();
+ });
+ });
+
+ describe('version()', function () {
+
+ it('returns the correct package version number', function (done) {
+
+ expect(Hawk.utils.version()).to.equal(Package.version);
+ done();
+ });
+ });
+
+ describe('unauthorized()', function () {
+
+ it('returns a hawk 401', function (done) {
+
+ expect(Hawk.utils.unauthorized('kaboom').output.headers['WWW-Authenticate']).to.equal('Hawk error="kaboom"');
+ done();
+ });
+
+ it('supports attributes', function (done) {
+
+ expect(Hawk.utils.unauthorized('kaboom', { a: 'b' }).output.headers['WWW-Authenticate']).to.equal('Hawk a="b", error="kaboom"');
+ done();
+ });
+ });
+});
diff --git a/node_modules/request/node_modules/mime-db/HISTORY.md b/node_modules/request/node_modules/mime-db/HISTORY.md
new file mode 100644
index 000000000..fa40614d9
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/HISTORY.md
@@ -0,0 +1,241 @@
+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
diff --git a/node_modules/request/node_modules/mime-db/LICENSE b/node_modules/request/node_modules/mime-db/LICENSE
new file mode 100644
index 000000000..a7ae8ee9b
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/LICENSE
@@ -0,0 +1,22 @@
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Jonathan Ong me@jongleberry.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/request/node_modules/mime-db/README.md b/node_modules/request/node_modules/mime-db/README.md
new file mode 100644
index 000000000..164cca030
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/README.md
@@ -0,0 +1,82 @@
+# mime-db
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][npm-url]
+[![Node.js Version][node-image]][node-url]
+[![Build Status][travis-image]][travis-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+
+This is a database of all mime types.
+It consists of a single, public JSON file and does not include any logic,
+allowing it to remain as un-opinionated as possible with an API.
+It aggregates data from the following sources:
+
+- http://www.iana.org/assignments/media-types/media-types.xhtml
+- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
+- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types
+
+## Installation
+
+```bash
+npm install mime-db
+```
+
+### Database Download
+
+If you're crazy enough to use this in the browser, you can just grab the
+JSON file using [RawGit](https://rawgit.com/). It is recommended to replace
+`master` with [a release tag](https://github.com/jshttp/mime-db/tags) as the
+JSON format may change in the future.
+
+```
+https://cdn.rawgit.com/jshttp/mime-db/master/db.json
+```
+
+## Usage
+
+```js
+var db = require('mime-db');
+
+// grab data on .js files
+var data = db['application/javascript'];
+```
+
+## Data Structure
+
+The JSON file is a map lookup for lowercased mime types.
+Each mime type has the following properties:
+
+- `.source` - where the mime type is defined.
+ If not set, it's probably a custom media type.
+ - `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
+ - `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
+ - `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)
+- `.extensions[]` - known extensions associated with this mime type.
+- `.compressible` - whether a file of this type is can be gzipped.
+- `.charset` - the default charset associated with this type, if any.
+
+If unknown, every property could be `undefined`.
+
+## Contributing
+
+To edit the database, only make PRs against `src/custom.json` or
+`src/custom-suffix.json`.
+
+To update the build, run `npm run build`.
+
+## Adding Custom Media Types
+
+The best way to get new media types included in this library is to register
+them with the IANA. The community registration procedure is outlined in
+[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types
+registered with the IANA are automatically pulled into this library.
+
+[npm-version-image]: https://img.shields.io/npm/v/mime-db.svg
+[npm-downloads-image]: https://img.shields.io/npm/dm/mime-db.svg
+[npm-url]: https://npmjs.org/package/mime-db
+[travis-image]: https://img.shields.io/travis/jshttp/mime-db/master.svg
+[travis-url]: https://travis-ci.org/jshttp/mime-db
+[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-db/master.svg
+[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
+[node-image]: https://img.shields.io/node/v/mime-db.svg
+[node-url]: http://nodejs.org/download/
diff --git a/node_modules/request/node_modules/mime-db/db.json b/node_modules/request/node_modules/mime-db/db.json
new file mode 100644
index 000000000..2f2dc448e
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/db.json
@@ -0,0 +1,6424 @@
+{
+ "application/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "application/3gpdash-qoe-report+xml": {
+ "source": "iana"
+ },
+ "application/3gpp-ims+xml": {
+ "source": "iana"
+ },
+ "application/a2l": {
+ "source": "iana"
+ },
+ "application/activemessage": {
+ "source": "iana"
+ },
+ "application/alto-costmap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-costmapfilter+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-directory+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointcost+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointcostparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointprop+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointpropparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-error+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-networkmap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-networkmapfilter+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/aml": {
+ "source": "iana"
+ },
+ "application/andrew-inset": {
+ "source": "iana",
+ "extensions": ["ez"]
+ },
+ "application/applefile": {
+ "source": "iana"
+ },
+ "application/applixware": {
+ "source": "apache",
+ "extensions": ["aw"]
+ },
+ "application/atf": {
+ "source": "iana"
+ },
+ "application/atfx": {
+ "source": "iana"
+ },
+ "application/atom+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["atom"]
+ },
+ "application/atomcat+xml": {
+ "source": "iana",
+ "extensions": ["atomcat"]
+ },
+ "application/atomdeleted+xml": {
+ "source": "iana"
+ },
+ "application/atomicmail": {
+ "source": "iana"
+ },
+ "application/atomsvc+xml": {
+ "source": "iana",
+ "extensions": ["atomsvc"]
+ },
+ "application/atxml": {
+ "source": "iana"
+ },
+ "application/auth-policy+xml": {
+ "source": "iana"
+ },
+ "application/bacnet-xdd+zip": {
+ "source": "iana"
+ },
+ "application/batch-smtp": {
+ "source": "iana"
+ },
+ "application/bdoc": {
+ "compressible": false,
+ "extensions": ["bdoc"]
+ },
+ "application/beep+xml": {
+ "source": "iana"
+ },
+ "application/calendar+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/calendar+xml": {
+ "source": "iana"
+ },
+ "application/call-completion": {
+ "source": "iana"
+ },
+ "application/cals-1840": {
+ "source": "iana"
+ },
+ "application/cbor": {
+ "source": "iana"
+ },
+ "application/ccmp+xml": {
+ "source": "iana"
+ },
+ "application/ccxml+xml": {
+ "source": "iana",
+ "extensions": ["ccxml"]
+ },
+ "application/cdfx+xml": {
+ "source": "iana"
+ },
+ "application/cdmi-capability": {
+ "source": "iana",
+ "extensions": ["cdmia"]
+ },
+ "application/cdmi-container": {
+ "source": "iana",
+ "extensions": ["cdmic"]
+ },
+ "application/cdmi-domain": {
+ "source": "iana",
+ "extensions": ["cdmid"]
+ },
+ "application/cdmi-object": {
+ "source": "iana",
+ "extensions": ["cdmio"]
+ },
+ "application/cdmi-queue": {
+ "source": "iana",
+ "extensions": ["cdmiq"]
+ },
+ "application/cea": {
+ "source": "iana"
+ },
+ "application/cea-2018+xml": {
+ "source": "iana"
+ },
+ "application/cellml+xml": {
+ "source": "iana"
+ },
+ "application/cfw": {
+ "source": "iana"
+ },
+ "application/cms": {
+ "source": "iana"
+ },
+ "application/cnrp+xml": {
+ "source": "iana"
+ },
+ "application/coap-group+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/commonground": {
+ "source": "iana"
+ },
+ "application/conference-info+xml": {
+ "source": "iana"
+ },
+ "application/cpl+xml": {
+ "source": "iana"
+ },
+ "application/csrattrs": {
+ "source": "iana"
+ },
+ "application/csta+xml": {
+ "source": "iana"
+ },
+ "application/cstadata+xml": {
+ "source": "iana"
+ },
+ "application/cu-seeme": {
+ "source": "apache",
+ "extensions": ["cu"]
+ },
+ "application/cybercash": {
+ "source": "iana"
+ },
+ "application/dart": {
+ "compressible": true
+ },
+ "application/dash+xml": {
+ "source": "iana",
+ "extensions": ["mdp"]
+ },
+ "application/dashdelta": {
+ "source": "iana"
+ },
+ "application/davmount+xml": {
+ "source": "iana",
+ "extensions": ["davmount"]
+ },
+ "application/dca-rft": {
+ "source": "iana"
+ },
+ "application/dcd": {
+ "source": "iana"
+ },
+ "application/dec-dx": {
+ "source": "iana"
+ },
+ "application/dialog-info+xml": {
+ "source": "iana"
+ },
+ "application/dicom": {
+ "source": "iana"
+ },
+ "application/dii": {
+ "source": "iana"
+ },
+ "application/dit": {
+ "source": "iana"
+ },
+ "application/dns": {
+ "source": "iana"
+ },
+ "application/docbook+xml": {
+ "source": "apache",
+ "extensions": ["dbk"]
+ },
+ "application/dskpp+xml": {
+ "source": "iana"
+ },
+ "application/dssc+der": {
+ "source": "iana",
+ "extensions": ["dssc"]
+ },
+ "application/dssc+xml": {
+ "source": "iana",
+ "extensions": ["xdssc"]
+ },
+ "application/dvcs": {
+ "source": "iana"
+ },
+ "application/ecmascript": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ecma"]
+ },
+ "application/edi-consent": {
+ "source": "iana"
+ },
+ "application/edi-x12": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/edifact": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/emma+xml": {
+ "source": "iana",
+ "extensions": ["emma"]
+ },
+ "application/emotionml+xml": {
+ "source": "iana"
+ },
+ "application/encaprtp": {
+ "source": "iana"
+ },
+ "application/epp+xml": {
+ "source": "iana"
+ },
+ "application/epub+zip": {
+ "source": "iana",
+ "extensions": ["epub"]
+ },
+ "application/eshop": {
+ "source": "iana"
+ },
+ "application/exi": {
+ "source": "iana",
+ "extensions": ["exi"]
+ },
+ "application/fastinfoset": {
+ "source": "iana"
+ },
+ "application/fastsoap": {
+ "source": "iana"
+ },
+ "application/fdt+xml": {
+ "source": "iana"
+ },
+ "application/fits": {
+ "source": "iana"
+ },
+ "application/font-sfnt": {
+ "source": "iana"
+ },
+ "application/font-tdpfr": {
+ "source": "iana",
+ "extensions": ["pfr"]
+ },
+ "application/font-woff": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["woff"]
+ },
+ "application/font-woff2": {
+ "compressible": false,
+ "extensions": ["woff2"]
+ },
+ "application/framework-attributes+xml": {
+ "source": "iana"
+ },
+ "application/gml+xml": {
+ "source": "apache",
+ "extensions": ["gml"]
+ },
+ "application/gpx+xml": {
+ "source": "apache",
+ "extensions": ["gpx"]
+ },
+ "application/gxf": {
+ "source": "apache",
+ "extensions": ["gxf"]
+ },
+ "application/gzip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/h224": {
+ "source": "iana"
+ },
+ "application/held+xml": {
+ "source": "iana"
+ },
+ "application/http": {
+ "source": "iana"
+ },
+ "application/hyperstudio": {
+ "source": "iana",
+ "extensions": ["stk"]
+ },
+ "application/ibe-key-request+xml": {
+ "source": "iana"
+ },
+ "application/ibe-pkg-reply+xml": {
+ "source": "iana"
+ },
+ "application/ibe-pp-data": {
+ "source": "iana"
+ },
+ "application/iges": {
+ "source": "iana"
+ },
+ "application/im-iscomposing+xml": {
+ "source": "iana"
+ },
+ "application/index": {
+ "source": "iana"
+ },
+ "application/index.cmd": {
+ "source": "iana"
+ },
+ "application/index.obj": {
+ "source": "iana"
+ },
+ "application/index.response": {
+ "source": "iana"
+ },
+ "application/index.vnd": {
+ "source": "iana"
+ },
+ "application/inkml+xml": {
+ "source": "iana",
+ "extensions": ["ink","inkml"]
+ },
+ "application/iotp": {
+ "source": "iana"
+ },
+ "application/ipfix": {
+ "source": "iana",
+ "extensions": ["ipfix"]
+ },
+ "application/ipp": {
+ "source": "iana"
+ },
+ "application/isup": {
+ "source": "iana"
+ },
+ "application/its+xml": {
+ "source": "iana"
+ },
+ "application/java-archive": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["jar","war","ear"]
+ },
+ "application/java-serialized-object": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["ser"]
+ },
+ "application/java-vm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["class"]
+ },
+ "application/javascript": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["js"]
+ },
+ "application/jose": {
+ "source": "iana"
+ },
+ "application/jose+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jrd+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/json": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["json","map"]
+ },
+ "application/json-patch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/json-seq": {
+ "source": "iana"
+ },
+ "application/json5": {
+ "extensions": ["json5"]
+ },
+ "application/jsonml+json": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["jsonml"]
+ },
+ "application/jwk+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jwk-set+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jwt": {
+ "source": "iana"
+ },
+ "application/kpml-request+xml": {
+ "source": "iana"
+ },
+ "application/kpml-response+xml": {
+ "source": "iana"
+ },
+ "application/ld+json": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["jsonld"]
+ },
+ "application/link-format": {
+ "source": "iana"
+ },
+ "application/load-control+xml": {
+ "source": "iana"
+ },
+ "application/lost+xml": {
+ "source": "iana",
+ "extensions": ["lostxml"]
+ },
+ "application/lostsync+xml": {
+ "source": "iana"
+ },
+ "application/lxf": {
+ "source": "iana"
+ },
+ "application/mac-binhex40": {
+ "source": "iana",
+ "extensions": ["hqx"]
+ },
+ "application/mac-compactpro": {
+ "source": "apache",
+ "extensions": ["cpt"]
+ },
+ "application/macwriteii": {
+ "source": "iana"
+ },
+ "application/mads+xml": {
+ "source": "iana",
+ "extensions": ["mads"]
+ },
+ "application/manifest+json": {
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["webmanifest"]
+ },
+ "application/marc": {
+ "source": "iana",
+ "extensions": ["mrc"]
+ },
+ "application/marcxml+xml": {
+ "source": "iana",
+ "extensions": ["mrcx"]
+ },
+ "application/mathematica": {
+ "source": "iana",
+ "extensions": ["ma","nb","mb"]
+ },
+ "application/mathml+xml": {
+ "source": "iana",
+ "extensions": ["mathml"]
+ },
+ "application/mathml-content+xml": {
+ "source": "iana"
+ },
+ "application/mathml-presentation+xml": {
+ "source": "iana"
+ },
+ "application/mbms-associated-procedure-description+xml": {
+ "source": "iana"
+ },
+ "application/mbms-deregister+xml": {
+ "source": "iana"
+ },
+ "application/mbms-envelope+xml": {
+ "source": "iana"
+ },
+ "application/mbms-msk+xml": {
+ "source": "iana"
+ },
+ "application/mbms-msk-response+xml": {
+ "source": "iana"
+ },
+ "application/mbms-protection-description+xml": {
+ "source": "iana"
+ },
+ "application/mbms-reception-report+xml": {
+ "source": "iana"
+ },
+ "application/mbms-register+xml": {
+ "source": "iana"
+ },
+ "application/mbms-register-response+xml": {
+ "source": "iana"
+ },
+ "application/mbms-schedule+xml": {
+ "source": "iana"
+ },
+ "application/mbms-user-service-description+xml": {
+ "source": "iana"
+ },
+ "application/mbox": {
+ "source": "iana",
+ "extensions": ["mbox"]
+ },
+ "application/media-policy-dataset+xml": {
+ "source": "iana"
+ },
+ "application/media_control+xml": {
+ "source": "iana"
+ },
+ "application/mediaservercontrol+xml": {
+ "source": "iana",
+ "extensions": ["mscml"]
+ },
+ "application/merge-patch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/metalink+xml": {
+ "source": "apache",
+ "extensions": ["metalink"]
+ },
+ "application/metalink4+xml": {
+ "source": "iana",
+ "extensions": ["meta4"]
+ },
+ "application/mets+xml": {
+ "source": "iana",
+ "extensions": ["mets"]
+ },
+ "application/mf4": {
+ "source": "iana"
+ },
+ "application/mikey": {
+ "source": "iana"
+ },
+ "application/mods+xml": {
+ "source": "iana",
+ "extensions": ["mods"]
+ },
+ "application/moss-keys": {
+ "source": "iana"
+ },
+ "application/moss-signature": {
+ "source": "iana"
+ },
+ "application/mosskey-data": {
+ "source": "iana"
+ },
+ "application/mosskey-request": {
+ "source": "iana"
+ },
+ "application/mp21": {
+ "source": "iana",
+ "extensions": ["m21","mp21"]
+ },
+ "application/mp4": {
+ "source": "iana",
+ "extensions": ["mp4s","m4p"]
+ },
+ "application/mpeg4-generic": {
+ "source": "iana"
+ },
+ "application/mpeg4-iod": {
+ "source": "iana"
+ },
+ "application/mpeg4-iod-xmt": {
+ "source": "iana"
+ },
+ "application/mrb-consumer+xml": {
+ "source": "iana"
+ },
+ "application/mrb-publish+xml": {
+ "source": "iana"
+ },
+ "application/msc-ivr+xml": {
+ "source": "iana"
+ },
+ "application/msc-mixer+xml": {
+ "source": "iana"
+ },
+ "application/msword": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["doc","dot"]
+ },
+ "application/mxf": {
+ "source": "iana",
+ "extensions": ["mxf"]
+ },
+ "application/nasdata": {
+ "source": "iana"
+ },
+ "application/news-checkgroups": {
+ "source": "iana"
+ },
+ "application/news-groupinfo": {
+ "source": "iana"
+ },
+ "application/news-transmission": {
+ "source": "iana"
+ },
+ "application/nlsml+xml": {
+ "source": "iana"
+ },
+ "application/nss": {
+ "source": "iana"
+ },
+ "application/ocsp-request": {
+ "source": "iana"
+ },
+ "application/ocsp-response": {
+ "source": "iana"
+ },
+ "application/octet-stream": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]
+ },
+ "application/oda": {
+ "source": "iana",
+ "extensions": ["oda"]
+ },
+ "application/odx": {
+ "source": "iana"
+ },
+ "application/oebps-package+xml": {
+ "source": "iana",
+ "extensions": ["opf"]
+ },
+ "application/ogg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ogx"]
+ },
+ "application/omdoc+xml": {
+ "source": "apache",
+ "extensions": ["omdoc"]
+ },
+ "application/onenote": {
+ "source": "apache",
+ "extensions": ["onetoc","onetoc2","onetmp","onepkg"]
+ },
+ "application/oxps": {
+ "source": "iana",
+ "extensions": ["oxps"]
+ },
+ "application/p2p-overlay+xml": {
+ "source": "iana"
+ },
+ "application/parityfec": {
+ "source": "iana"
+ },
+ "application/patch-ops-error+xml": {
+ "source": "iana",
+ "extensions": ["xer"]
+ },
+ "application/pdf": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pdf"]
+ },
+ "application/pdx": {
+ "source": "iana"
+ },
+ "application/pgp-encrypted": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pgp"]
+ },
+ "application/pgp-keys": {
+ "source": "iana"
+ },
+ "application/pgp-signature": {
+ "source": "iana",
+ "extensions": ["asc","sig"]
+ },
+ "application/pics-rules": {
+ "source": "apache",
+ "extensions": ["prf"]
+ },
+ "application/pidf+xml": {
+ "source": "iana"
+ },
+ "application/pidf-diff+xml": {
+ "source": "iana"
+ },
+ "application/pkcs10": {
+ "source": "iana",
+ "extensions": ["p10"]
+ },
+ "application/pkcs7-mime": {
+ "source": "iana",
+ "extensions": ["p7m","p7c"]
+ },
+ "application/pkcs7-signature": {
+ "source": "iana",
+ "extensions": ["p7s"]
+ },
+ "application/pkcs8": {
+ "source": "iana",
+ "extensions": ["p8"]
+ },
+ "application/pkix-attr-cert": {
+ "source": "iana",
+ "extensions": ["ac"]
+ },
+ "application/pkix-cert": {
+ "source": "iana",
+ "extensions": ["cer"]
+ },
+ "application/pkix-crl": {
+ "source": "iana",
+ "extensions": ["crl"]
+ },
+ "application/pkix-pkipath": {
+ "source": "iana",
+ "extensions": ["pkipath"]
+ },
+ "application/pkixcmp": {
+ "source": "iana",
+ "extensions": ["pki"]
+ },
+ "application/pls+xml": {
+ "source": "iana",
+ "extensions": ["pls"]
+ },
+ "application/poc-settings+xml": {
+ "source": "iana"
+ },
+ "application/postscript": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ai","eps","ps"]
+ },
+ "application/provenance+xml": {
+ "source": "iana"
+ },
+ "application/prs.alvestrand.titrax-sheet": {
+ "source": "iana"
+ },
+ "application/prs.cww": {
+ "source": "iana",
+ "extensions": ["cww"]
+ },
+ "application/prs.hpub+zip": {
+ "source": "iana"
+ },
+ "application/prs.nprend": {
+ "source": "iana"
+ },
+ "application/prs.plucker": {
+ "source": "iana"
+ },
+ "application/prs.rdf-xml-crypt": {
+ "source": "iana"
+ },
+ "application/prs.xsf+xml": {
+ "source": "iana"
+ },
+ "application/pskc+xml": {
+ "source": "iana",
+ "extensions": ["pskcxml"]
+ },
+ "application/qsig": {
+ "source": "iana"
+ },
+ "application/raptorfec": {
+ "source": "iana"
+ },
+ "application/rdap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/rdf+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rdf"]
+ },
+ "application/reginfo+xml": {
+ "source": "iana",
+ "extensions": ["rif"]
+ },
+ "application/relax-ng-compact-syntax": {
+ "source": "iana",
+ "extensions": ["rnc"]
+ },
+ "application/remote-printing": {
+ "source": "iana"
+ },
+ "application/reputon+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/resource-lists+xml": {
+ "source": "iana",
+ "extensions": ["rl"]
+ },
+ "application/resource-lists-diff+xml": {
+ "source": "iana",
+ "extensions": ["rld"]
+ },
+ "application/riscos": {
+ "source": "iana"
+ },
+ "application/rlmi+xml": {
+ "source": "iana"
+ },
+ "application/rls-services+xml": {
+ "source": "iana",
+ "extensions": ["rs"]
+ },
+ "application/rpki-ghostbusters": {
+ "source": "iana",
+ "extensions": ["gbr"]
+ },
+ "application/rpki-manifest": {
+ "source": "iana",
+ "extensions": ["mft"]
+ },
+ "application/rpki-roa": {
+ "source": "iana",
+ "extensions": ["roa"]
+ },
+ "application/rpki-updown": {
+ "source": "iana"
+ },
+ "application/rsd+xml": {
+ "source": "apache",
+ "extensions": ["rsd"]
+ },
+ "application/rss+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["rss"]
+ },
+ "application/rtf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtf"]
+ },
+ "application/rtploopback": {
+ "source": "iana"
+ },
+ "application/rtx": {
+ "source": "iana"
+ },
+ "application/samlassertion+xml": {
+ "source": "iana"
+ },
+ "application/samlmetadata+xml": {
+ "source": "iana"
+ },
+ "application/sbml+xml": {
+ "source": "iana",
+ "extensions": ["sbml"]
+ },
+ "application/scaip+xml": {
+ "source": "iana"
+ },
+ "application/scim+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/scvp-cv-request": {
+ "source": "iana",
+ "extensions": ["scq"]
+ },
+ "application/scvp-cv-response": {
+ "source": "iana",
+ "extensions": ["scs"]
+ },
+ "application/scvp-vp-request": {
+ "source": "iana",
+ "extensions": ["spq"]
+ },
+ "application/scvp-vp-response": {
+ "source": "iana",
+ "extensions": ["spp"]
+ },
+ "application/sdp": {
+ "source": "iana",
+ "extensions": ["sdp"]
+ },
+ "application/sep+xml": {
+ "source": "iana"
+ },
+ "application/sep-exi": {
+ "source": "iana"
+ },
+ "application/session-info": {
+ "source": "iana"
+ },
+ "application/set-payment": {
+ "source": "iana"
+ },
+ "application/set-payment-initiation": {
+ "source": "iana",
+ "extensions": ["setpay"]
+ },
+ "application/set-registration": {
+ "source": "iana"
+ },
+ "application/set-registration-initiation": {
+ "source": "iana",
+ "extensions": ["setreg"]
+ },
+ "application/sgml": {
+ "source": "iana"
+ },
+ "application/sgml-open-catalog": {
+ "source": "iana"
+ },
+ "application/shf+xml": {
+ "source": "iana",
+ "extensions": ["shf"]
+ },
+ "application/sieve": {
+ "source": "iana"
+ },
+ "application/simple-filter+xml": {
+ "source": "iana"
+ },
+ "application/simple-message-summary": {
+ "source": "iana"
+ },
+ "application/simplesymbolcontainer": {
+ "source": "iana"
+ },
+ "application/slate": {
+ "source": "iana"
+ },
+ "application/smil": {
+ "source": "iana"
+ },
+ "application/smil+xml": {
+ "source": "iana",
+ "extensions": ["smi","smil"]
+ },
+ "application/smpte336m": {
+ "source": "iana"
+ },
+ "application/soap+fastinfoset": {
+ "source": "iana"
+ },
+ "application/soap+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sparql-query": {
+ "source": "iana",
+ "extensions": ["rq"]
+ },
+ "application/sparql-results+xml": {
+ "source": "iana",
+ "extensions": ["srx"]
+ },
+ "application/spirits-event+xml": {
+ "source": "iana"
+ },
+ "application/sql": {
+ "source": "iana"
+ },
+ "application/srgs": {
+ "source": "iana",
+ "extensions": ["gram"]
+ },
+ "application/srgs+xml": {
+ "source": "iana",
+ "extensions": ["grxml"]
+ },
+ "application/sru+xml": {
+ "source": "iana",
+ "extensions": ["sru"]
+ },
+ "application/ssdl+xml": {
+ "source": "apache",
+ "extensions": ["ssdl"]
+ },
+ "application/ssml+xml": {
+ "source": "iana",
+ "extensions": ["ssml"]
+ },
+ "application/tamp-apex-update": {
+ "source": "iana"
+ },
+ "application/tamp-apex-update-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-community-update": {
+ "source": "iana"
+ },
+ "application/tamp-community-update-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-error": {
+ "source": "iana"
+ },
+ "application/tamp-sequence-adjust": {
+ "source": "iana"
+ },
+ "application/tamp-sequence-adjust-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-status-query": {
+ "source": "iana"
+ },
+ "application/tamp-status-response": {
+ "source": "iana"
+ },
+ "application/tamp-update": {
+ "source": "iana"
+ },
+ "application/tamp-update-confirm": {
+ "source": "iana"
+ },
+ "application/tar": {
+ "compressible": true
+ },
+ "application/tei+xml": {
+ "source": "iana",
+ "extensions": ["tei","teicorpus"]
+ },
+ "application/thraud+xml": {
+ "source": "iana",
+ "extensions": ["tfi"]
+ },
+ "application/timestamp-query": {
+ "source": "iana"
+ },
+ "application/timestamp-reply": {
+ "source": "iana"
+ },
+ "application/timestamped-data": {
+ "source": "iana",
+ "extensions": ["tsd"]
+ },
+ "application/ttml+xml": {
+ "source": "iana"
+ },
+ "application/tve-trigger": {
+ "source": "iana"
+ },
+ "application/ulpfec": {
+ "source": "iana"
+ },
+ "application/urc-grpsheet+xml": {
+ "source": "iana"
+ },
+ "application/urc-ressheet+xml": {
+ "source": "iana"
+ },
+ "application/urc-targetdesc+xml": {
+ "source": "iana"
+ },
+ "application/urc-uisocketdesc+xml": {
+ "source": "iana"
+ },
+ "application/vcard+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vcard+xml": {
+ "source": "iana"
+ },
+ "application/vemmi": {
+ "source": "iana"
+ },
+ "application/vividence.scriptfile": {
+ "source": "apache"
+ },
+ "application/vnd.3gpp.bsf+xml": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.pic-bw-large": {
+ "source": "iana",
+ "extensions": ["plb"]
+ },
+ "application/vnd.3gpp.pic-bw-small": {
+ "source": "iana",
+ "extensions": ["psb"]
+ },
+ "application/vnd.3gpp.pic-bw-var": {
+ "source": "iana",
+ "extensions": ["pvb"]
+ },
+ "application/vnd.3gpp.sms": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.ussd+xml": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp2.bcmcsinfo+xml": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp2.sms": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp2.tcap": {
+ "source": "iana",
+ "extensions": ["tcap"]
+ },
+ "application/vnd.3m.post-it-notes": {
+ "source": "iana",
+ "extensions": ["pwn"]
+ },
+ "application/vnd.accpac.simply.aso": {
+ "source": "iana",
+ "extensions": ["aso"]
+ },
+ "application/vnd.accpac.simply.imp": {
+ "source": "iana",
+ "extensions": ["imp"]
+ },
+ "application/vnd.acucobol": {
+ "source": "iana",
+ "extensions": ["acu"]
+ },
+ "application/vnd.acucorp": {
+ "source": "iana",
+ "extensions": ["atc","acutc"]
+ },
+ "application/vnd.adobe.air-application-installer-package+zip": {
+ "source": "apache",
+ "extensions": ["air"]
+ },
+ "application/vnd.adobe.flash.movie": {
+ "source": "iana"
+ },
+ "application/vnd.adobe.formscentral.fcdt": {
+ "source": "iana",
+ "extensions": ["fcdt"]
+ },
+ "application/vnd.adobe.fxp": {
+ "source": "iana",
+ "extensions": ["fxp","fxpl"]
+ },
+ "application/vnd.adobe.partial-upload": {
+ "source": "iana"
+ },
+ "application/vnd.adobe.xdp+xml": {
+ "source": "iana",
+ "extensions": ["xdp"]
+ },
+ "application/vnd.adobe.xfdf": {
+ "source": "iana",
+ "extensions": ["xfdf"]
+ },
+ "application/vnd.aether.imp": {
+ "source": "iana"
+ },
+ "application/vnd.ah-barcode": {
+ "source": "iana"
+ },
+ "application/vnd.ahead.space": {
+ "source": "iana",
+ "extensions": ["ahead"]
+ },
+ "application/vnd.airzip.filesecure.azf": {
+ "source": "iana",
+ "extensions": ["azf"]
+ },
+ "application/vnd.airzip.filesecure.azs": {
+ "source": "iana",
+ "extensions": ["azs"]
+ },
+ "application/vnd.amazon.ebook": {
+ "source": "apache",
+ "extensions": ["azw"]
+ },
+ "application/vnd.americandynamics.acc": {
+ "source": "iana",
+ "extensions": ["acc"]
+ },
+ "application/vnd.amiga.ami": {
+ "source": "iana",
+ "extensions": ["ami"]
+ },
+ "application/vnd.amundsen.maze+xml": {
+ "source": "iana"
+ },
+ "application/vnd.android.package-archive": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["apk"]
+ },
+ "application/vnd.anser-web-certificate-issue-initiation": {
+ "source": "iana",
+ "extensions": ["cii"]
+ },
+ "application/vnd.anser-web-funds-transfer-initiation": {
+ "source": "apache",
+ "extensions": ["fti"]
+ },
+ "application/vnd.antix.game-component": {
+ "source": "iana",
+ "extensions": ["atx"]
+ },
+ "application/vnd.apache.thrift.binary": {
+ "source": "iana"
+ },
+ "application/vnd.apache.thrift.compact": {
+ "source": "iana"
+ },
+ "application/vnd.apache.thrift.json": {
+ "source": "iana"
+ },
+ "application/vnd.api+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.apple.installer+xml": {
+ "source": "iana",
+ "extensions": ["mpkg"]
+ },
+ "application/vnd.apple.mpegurl": {
+ "source": "iana",
+ "extensions": ["m3u8"]
+ },
+ "application/vnd.arastra.swi": {
+ "source": "iana"
+ },
+ "application/vnd.aristanetworks.swi": {
+ "source": "iana",
+ "extensions": ["swi"]
+ },
+ "application/vnd.artsquare": {
+ "source": "iana"
+ },
+ "application/vnd.astraea-software.iota": {
+ "source": "iana",
+ "extensions": ["iota"]
+ },
+ "application/vnd.audiograph": {
+ "source": "iana",
+ "extensions": ["aep"]
+ },
+ "application/vnd.autopackage": {
+ "source": "iana"
+ },
+ "application/vnd.avistar+xml": {
+ "source": "iana"
+ },
+ "application/vnd.balsamiq.bmml+xml": {
+ "source": "iana"
+ },
+ "application/vnd.balsamiq.bmpr": {
+ "source": "iana"
+ },
+ "application/vnd.bekitzur-stech+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.biopax.rdf+xml": {
+ "source": "iana"
+ },
+ "application/vnd.blueice.multipass": {
+ "source": "iana",
+ "extensions": ["mpm"]
+ },
+ "application/vnd.bluetooth.ep.oob": {
+ "source": "iana"
+ },
+ "application/vnd.bluetooth.le.oob": {
+ "source": "iana"
+ },
+ "application/vnd.bmi": {
+ "source": "iana",
+ "extensions": ["bmi"]
+ },
+ "application/vnd.businessobjects": {
+ "source": "iana",
+ "extensions": ["rep"]
+ },
+ "application/vnd.cab-jscript": {
+ "source": "iana"
+ },
+ "application/vnd.canon-cpdl": {
+ "source": "iana"
+ },
+ "application/vnd.canon-lips": {
+ "source": "iana"
+ },
+ "application/vnd.cendio.thinlinc.clientconf": {
+ "source": "iana"
+ },
+ "application/vnd.century-systems.tcp_stream": {
+ "source": "iana"
+ },
+ "application/vnd.chemdraw+xml": {
+ "source": "iana",
+ "extensions": ["cdxml"]
+ },
+ "application/vnd.chipnuts.karaoke-mmd": {
+ "source": "iana",
+ "extensions": ["mmd"]
+ },
+ "application/vnd.cinderella": {
+ "source": "iana",
+ "extensions": ["cdy"]
+ },
+ "application/vnd.cirpack.isdn-ext": {
+ "source": "iana"
+ },
+ "application/vnd.citationstyles.style+xml": {
+ "source": "iana"
+ },
+ "application/vnd.claymore": {
+ "source": "iana",
+ "extensions": ["cla"]
+ },
+ "application/vnd.cloanto.rp9": {
+ "source": "iana",
+ "extensions": ["rp9"]
+ },
+ "application/vnd.clonk.c4group": {
+ "source": "iana",
+ "extensions": ["c4g","c4d","c4f","c4p","c4u"]
+ },
+ "application/vnd.cluetrust.cartomobile-config": {
+ "source": "iana",
+ "extensions": ["c11amc"]
+ },
+ "application/vnd.cluetrust.cartomobile-config-pkg": {
+ "source": "iana",
+ "extensions": ["c11amz"]
+ },
+ "application/vnd.coffeescript": {
+ "source": "iana"
+ },
+ "application/vnd.collection+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.collection.doc+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.collection.next+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.commerce-battelle": {
+ "source": "iana"
+ },
+ "application/vnd.commonspace": {
+ "source": "iana",
+ "extensions": ["csp"]
+ },
+ "application/vnd.contact.cmsg": {
+ "source": "iana",
+ "extensions": ["cdbcmsg"]
+ },
+ "application/vnd.cosmocaller": {
+ "source": "iana",
+ "extensions": ["cmc"]
+ },
+ "application/vnd.crick.clicker": {
+ "source": "iana",
+ "extensions": ["clkx"]
+ },
+ "application/vnd.crick.clicker.keyboard": {
+ "source": "iana",
+ "extensions": ["clkk"]
+ },
+ "application/vnd.crick.clicker.palette": {
+ "source": "iana",
+ "extensions": ["clkp"]
+ },
+ "application/vnd.crick.clicker.template": {
+ "source": "iana",
+ "extensions": ["clkt"]
+ },
+ "application/vnd.crick.clicker.wordbank": {
+ "source": "iana",
+ "extensions": ["clkw"]
+ },
+ "application/vnd.criticaltools.wbs+xml": {
+ "source": "iana",
+ "extensions": ["wbs"]
+ },
+ "application/vnd.ctc-posml": {
+ "source": "iana",
+ "extensions": ["pml"]
+ },
+ "application/vnd.ctct.ws+xml": {
+ "source": "iana"
+ },
+ "application/vnd.cups-pdf": {
+ "source": "iana"
+ },
+ "application/vnd.cups-postscript": {
+ "source": "iana"
+ },
+ "application/vnd.cups-ppd": {
+ "source": "iana",
+ "extensions": ["ppd"]
+ },
+ "application/vnd.cups-raster": {
+ "source": "iana"
+ },
+ "application/vnd.cups-raw": {
+ "source": "iana"
+ },
+ "application/vnd.curl": {
+ "source": "iana"
+ },
+ "application/vnd.curl.car": {
+ "source": "apache",
+ "extensions": ["car"]
+ },
+ "application/vnd.curl.pcurl": {
+ "source": "apache",
+ "extensions": ["pcurl"]
+ },
+ "application/vnd.cyan.dean.root+xml": {
+ "source": "iana"
+ },
+ "application/vnd.cybank": {
+ "source": "iana"
+ },
+ "application/vnd.dart": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dart"]
+ },
+ "application/vnd.data-vision.rdz": {
+ "source": "iana",
+ "extensions": ["rdz"]
+ },
+ "application/vnd.debian.binary-package": {
+ "source": "iana"
+ },
+ "application/vnd.dece.data": {
+ "source": "iana",
+ "extensions": ["uvf","uvvf","uvd","uvvd"]
+ },
+ "application/vnd.dece.ttml+xml": {
+ "source": "iana",
+ "extensions": ["uvt","uvvt"]
+ },
+ "application/vnd.dece.unspecified": {
+ "source": "iana",
+ "extensions": ["uvx","uvvx"]
+ },
+ "application/vnd.dece.zip": {
+ "source": "iana",
+ "extensions": ["uvz","uvvz"]
+ },
+ "application/vnd.denovo.fcselayout-link": {
+ "source": "iana",
+ "extensions": ["fe_launch"]
+ },
+ "application/vnd.desmume-movie": {
+ "source": "iana"
+ },
+ "application/vnd.dir-bi.plate-dl-nosuffix": {
+ "source": "iana"
+ },
+ "application/vnd.dm.delegation+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dna": {
+ "source": "iana",
+ "extensions": ["dna"]
+ },
+ "application/vnd.document+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dolby.mlp": {
+ "source": "apache",
+ "extensions": ["mlp"]
+ },
+ "application/vnd.dolby.mobile.1": {
+ "source": "iana"
+ },
+ "application/vnd.dolby.mobile.2": {
+ "source": "iana"
+ },
+ "application/vnd.doremir.scorecloud-binary-document": {
+ "source": "iana"
+ },
+ "application/vnd.dpgraph": {
+ "source": "iana",
+ "extensions": ["dpg"]
+ },
+ "application/vnd.dreamfactory": {
+ "source": "iana",
+ "extensions": ["dfac"]
+ },
+ "application/vnd.ds-keypoint": {
+ "source": "apache",
+ "extensions": ["kpxx"]
+ },
+ "application/vnd.dtg.local": {
+ "source": "iana"
+ },
+ "application/vnd.dtg.local.flash": {
+ "source": "iana"
+ },
+ "application/vnd.dtg.local.html": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ait": {
+ "source": "iana",
+ "extensions": ["ait"]
+ },
+ "application/vnd.dvb.dvbj": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.esgcontainer": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcdftnotifaccess": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgaccess": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgaccess2": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgpdd": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcroaming": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.iptv.alfec-base": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.iptv.alfec-enhancement": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-aggregate-root+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-container+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-generic+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-ia-msglist+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-ia-registration-request+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-ia-registration-response+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-init+xml": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.pfr": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.service": {
+ "source": "iana",
+ "extensions": ["svc"]
+ },
+ "application/vnd.dxr": {
+ "source": "iana"
+ },
+ "application/vnd.dynageo": {
+ "source": "iana",
+ "extensions": ["geo"]
+ },
+ "application/vnd.dzr": {
+ "source": "iana"
+ },
+ "application/vnd.easykaraoke.cdgdownload": {
+ "source": "iana"
+ },
+ "application/vnd.ecdis-update": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.chart": {
+ "source": "iana",
+ "extensions": ["mag"]
+ },
+ "application/vnd.ecowin.filerequest": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.fileupdate": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.series": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.seriesrequest": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.seriesupdate": {
+ "source": "iana"
+ },
+ "application/vnd.emclient.accessrequest+xml": {
+ "source": "iana"
+ },
+ "application/vnd.enliven": {
+ "source": "iana",
+ "extensions": ["nml"]
+ },
+ "application/vnd.enphase.envoy": {
+ "source": "iana"
+ },
+ "application/vnd.eprints.data+xml": {
+ "source": "iana"
+ },
+ "application/vnd.epson.esf": {
+ "source": "iana",
+ "extensions": ["esf"]
+ },
+ "application/vnd.epson.msf": {
+ "source": "iana",
+ "extensions": ["msf"]
+ },
+ "application/vnd.epson.quickanime": {
+ "source": "iana",
+ "extensions": ["qam"]
+ },
+ "application/vnd.epson.salt": {
+ "source": "iana",
+ "extensions": ["slt"]
+ },
+ "application/vnd.epson.ssf": {
+ "source": "iana",
+ "extensions": ["ssf"]
+ },
+ "application/vnd.ericsson.quickcall": {
+ "source": "iana"
+ },
+ "application/vnd.eszigno3+xml": {
+ "source": "iana",
+ "extensions": ["es3","et3"]
+ },
+ "application/vnd.etsi.aoc+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.asic-e+zip": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.asic-s+zip": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.cug+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvcommand+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvdiscovery+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvprofile+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvsad-bc+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvsad-cod+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvsad-npvr+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvservice+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvsync+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.iptvueprofile+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.mcid+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.mheg5": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.overload-control-policy-dataset+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.pstn+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.sci+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.simservs+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.timestamp-token": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.tsl+xml": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.tsl.der": {
+ "source": "iana"
+ },
+ "application/vnd.eudora.data": {
+ "source": "iana"
+ },
+ "application/vnd.ezpix-album": {
+ "source": "iana",
+ "extensions": ["ez2"]
+ },
+ "application/vnd.ezpix-package": {
+ "source": "iana",
+ "extensions": ["ez3"]
+ },
+ "application/vnd.f-secure.mobile": {
+ "source": "iana"
+ },
+ "application/vnd.fastcopy-disk-image": {
+ "source": "iana"
+ },
+ "application/vnd.fdf": {
+ "source": "iana",
+ "extensions": ["fdf"]
+ },
+ "application/vnd.fdsn.mseed": {
+ "source": "iana",
+ "extensions": ["mseed"]
+ },
+ "application/vnd.fdsn.seed": {
+ "source": "iana",
+ "extensions": ["seed","dataless"]
+ },
+ "application/vnd.ffsns": {
+ "source": "iana"
+ },
+ "application/vnd.fints": {
+ "source": "iana"
+ },
+ "application/vnd.flographit": {
+ "source": "iana",
+ "extensions": ["gph"]
+ },
+ "application/vnd.fluxtime.clip": {
+ "source": "iana",
+ "extensions": ["ftc"]
+ },
+ "application/vnd.font-fontforge-sfd": {
+ "source": "iana"
+ },
+ "application/vnd.framemaker": {
+ "source": "iana",
+ "extensions": ["fm","frame","maker","book"]
+ },
+ "application/vnd.frogans.fnc": {
+ "source": "iana",
+ "extensions": ["fnc"]
+ },
+ "application/vnd.frogans.ltf": {
+ "source": "iana",
+ "extensions": ["ltf"]
+ },
+ "application/vnd.fsc.weblaunch": {
+ "source": "iana",
+ "extensions": ["fsc"]
+ },
+ "application/vnd.fujitsu.oasys": {
+ "source": "iana",
+ "extensions": ["oas"]
+ },
+ "application/vnd.fujitsu.oasys2": {
+ "source": "iana",
+ "extensions": ["oa2"]
+ },
+ "application/vnd.fujitsu.oasys3": {
+ "source": "iana",
+ "extensions": ["oa3"]
+ },
+ "application/vnd.fujitsu.oasysgp": {
+ "source": "iana",
+ "extensions": ["fg5"]
+ },
+ "application/vnd.fujitsu.oasysprs": {
+ "source": "iana",
+ "extensions": ["bh2"]
+ },
+ "application/vnd.fujixerox.art-ex": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.art4": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.ddd": {
+ "source": "iana",
+ "extensions": ["ddd"]
+ },
+ "application/vnd.fujixerox.docuworks": {
+ "source": "iana",
+ "extensions": ["xdw"]
+ },
+ "application/vnd.fujixerox.docuworks.binder": {
+ "source": "iana",
+ "extensions": ["xbd"]
+ },
+ "application/vnd.fujixerox.docuworks.container": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.hbpl": {
+ "source": "iana"
+ },
+ "application/vnd.fut-misnet": {
+ "source": "iana"
+ },
+ "application/vnd.fuzzysheet": {
+ "source": "iana",
+ "extensions": ["fzs"]
+ },
+ "application/vnd.genomatix.tuxedo": {
+ "source": "iana",
+ "extensions": ["txd"]
+ },
+ "application/vnd.geo+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.geocube+xml": {
+ "source": "iana"
+ },
+ "application/vnd.geogebra.file": {
+ "source": "iana",
+ "extensions": ["ggb"]
+ },
+ "application/vnd.geogebra.tool": {
+ "source": "iana",
+ "extensions": ["ggt"]
+ },
+ "application/vnd.geometry-explorer": {
+ "source": "iana",
+ "extensions": ["gex","gre"]
+ },
+ "application/vnd.geonext": {
+ "source": "iana",
+ "extensions": ["gxt"]
+ },
+ "application/vnd.geoplan": {
+ "source": "iana",
+ "extensions": ["g2w"]
+ },
+ "application/vnd.geospace": {
+ "source": "iana",
+ "extensions": ["g3w"]
+ },
+ "application/vnd.gerber": {
+ "source": "iana"
+ },
+ "application/vnd.globalplatform.card-content-mgt": {
+ "source": "iana"
+ },
+ "application/vnd.globalplatform.card-content-mgt-response": {
+ "source": "iana"
+ },
+ "application/vnd.gmx": {
+ "source": "iana",
+ "extensions": ["gmx"]
+ },
+ "application/vnd.google-earth.kml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["kml"]
+ },
+ "application/vnd.google-earth.kmz": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["kmz"]
+ },
+ "application/vnd.gov.sk.e-form+xml": {
+ "source": "iana"
+ },
+ "application/vnd.gov.sk.e-form+zip": {
+ "source": "iana"
+ },
+ "application/vnd.gov.sk.xmldatacontainer+xml": {
+ "source": "iana"
+ },
+ "application/vnd.grafeq": {
+ "source": "iana",
+ "extensions": ["gqf","gqs"]
+ },
+ "application/vnd.gridmp": {
+ "source": "iana"
+ },
+ "application/vnd.groove-account": {
+ "source": "iana",
+ "extensions": ["gac"]
+ },
+ "application/vnd.groove-help": {
+ "source": "iana",
+ "extensions": ["ghf"]
+ },
+ "application/vnd.groove-identity-message": {
+ "source": "iana",
+ "extensions": ["gim"]
+ },
+ "application/vnd.groove-injector": {
+ "source": "iana",
+ "extensions": ["grv"]
+ },
+ "application/vnd.groove-tool-message": {
+ "source": "iana",
+ "extensions": ["gtm"]
+ },
+ "application/vnd.groove-tool-template": {
+ "source": "iana",
+ "extensions": ["tpl"]
+ },
+ "application/vnd.groove-vcard": {
+ "source": "iana",
+ "extensions": ["vcg"]
+ },
+ "application/vnd.hal+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hal+xml": {
+ "source": "iana",
+ "extensions": ["hal"]
+ },
+ "application/vnd.handheld-entertainment+xml": {
+ "source": "iana",
+ "extensions": ["zmm"]
+ },
+ "application/vnd.hbci": {
+ "source": "iana",
+ "extensions": ["hbci"]
+ },
+ "application/vnd.hcl-bireports": {
+ "source": "iana"
+ },
+ "application/vnd.heroku+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hhe.lesson-player": {
+ "source": "iana",
+ "extensions": ["les"]
+ },
+ "application/vnd.hp-hpgl": {
+ "source": "iana",
+ "extensions": ["hpgl"]
+ },
+ "application/vnd.hp-hpid": {
+ "source": "iana",
+ "extensions": ["hpid"]
+ },
+ "application/vnd.hp-hps": {
+ "source": "iana",
+ "extensions": ["hps"]
+ },
+ "application/vnd.hp-jlyt": {
+ "source": "iana",
+ "extensions": ["jlt"]
+ },
+ "application/vnd.hp-pcl": {
+ "source": "iana",
+ "extensions": ["pcl"]
+ },
+ "application/vnd.hp-pclxl": {
+ "source": "iana",
+ "extensions": ["pclxl"]
+ },
+ "application/vnd.httphone": {
+ "source": "iana"
+ },
+ "application/vnd.hydrostatix.sof-data": {
+ "source": "iana",
+ "extensions": ["sfd-hdstx"]
+ },
+ "application/vnd.hyperdrive+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hzn-3d-crossword": {
+ "source": "iana"
+ },
+ "application/vnd.ibm.afplinedata": {
+ "source": "iana"
+ },
+ "application/vnd.ibm.electronic-media": {
+ "source": "iana"
+ },
+ "application/vnd.ibm.minipay": {
+ "source": "iana",
+ "extensions": ["mpy"]
+ },
+ "application/vnd.ibm.modcap": {
+ "source": "iana",
+ "extensions": ["afp","listafp","list3820"]
+ },
+ "application/vnd.ibm.rights-management": {
+ "source": "iana",
+ "extensions": ["irm"]
+ },
+ "application/vnd.ibm.secure-container": {
+ "source": "iana",
+ "extensions": ["sc"]
+ },
+ "application/vnd.iccprofile": {
+ "source": "iana",
+ "extensions": ["icc","icm"]
+ },
+ "application/vnd.ieee.1905": {
+ "source": "iana"
+ },
+ "application/vnd.igloader": {
+ "source": "iana",
+ "extensions": ["igl"]
+ },
+ "application/vnd.immervision-ivp": {
+ "source": "iana",
+ "extensions": ["ivp"]
+ },
+ "application/vnd.immervision-ivu": {
+ "source": "iana",
+ "extensions": ["ivu"]
+ },
+ "application/vnd.ims.imsccv1p1": {
+ "source": "iana"
+ },
+ "application/vnd.ims.imsccv1p2": {
+ "source": "iana"
+ },
+ "application/vnd.ims.imsccv1p3": {
+ "source": "iana"
+ },
+ "application/vnd.ims.lis.v2.result+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolconsumerprofile+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolproxy+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolproxy.id+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolsettings+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolsettings.simple+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.informedcontrol.rms+xml": {
+ "source": "iana"
+ },
+ "application/vnd.informix-visionary": {
+ "source": "iana"
+ },
+ "application/vnd.infotech.project": {
+ "source": "iana"
+ },
+ "application/vnd.infotech.project+xml": {
+ "source": "iana"
+ },
+ "application/vnd.innopath.wamp.notification": {
+ "source": "iana"
+ },
+ "application/vnd.insors.igm": {
+ "source": "iana",
+ "extensions": ["igm"]
+ },
+ "application/vnd.intercon.formnet": {
+ "source": "iana",
+ "extensions": ["xpw","xpx"]
+ },
+ "application/vnd.intergeo": {
+ "source": "iana",
+ "extensions": ["i2g"]
+ },
+ "application/vnd.intertrust.digibox": {
+ "source": "iana"
+ },
+ "application/vnd.intertrust.nncp": {
+ "source": "iana"
+ },
+ "application/vnd.intu.qbo": {
+ "source": "iana",
+ "extensions": ["qbo"]
+ },
+ "application/vnd.intu.qfx": {
+ "source": "iana",
+ "extensions": ["qfx"]
+ },
+ "application/vnd.iptc.g2.catalogitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.conceptitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.knowledgeitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.newsitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.newsmessage+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.packageitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.planningitem+xml": {
+ "source": "iana"
+ },
+ "application/vnd.ipunplugged.rcprofile": {
+ "source": "iana",
+ "extensions": ["rcprofile"]
+ },
+ "application/vnd.irepository.package+xml": {
+ "source": "iana",
+ "extensions": ["irp"]
+ },
+ "application/vnd.is-xpr": {
+ "source": "iana",
+ "extensions": ["xpr"]
+ },
+ "application/vnd.isac.fcs": {
+ "source": "iana",
+ "extensions": ["fcs"]
+ },
+ "application/vnd.jam": {
+ "source": "iana",
+ "extensions": ["jam"]
+ },
+ "application/vnd.japannet-directory-service": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-jpnstore-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-payment-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-registration": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-registration-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-setstore-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-verification": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-verification-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.jcp.javame.midlet-rms": {
+ "source": "iana",
+ "extensions": ["rms"]
+ },
+ "application/vnd.jisp": {
+ "source": "iana",
+ "extensions": ["jisp"]
+ },
+ "application/vnd.joost.joda-archive": {
+ "source": "iana",
+ "extensions": ["joda"]
+ },
+ "application/vnd.jsk.isdn-ngn": {
+ "source": "iana"
+ },
+ "application/vnd.kahootz": {
+ "source": "iana",
+ "extensions": ["ktz","ktr"]
+ },
+ "application/vnd.kde.karbon": {
+ "source": "iana",
+ "extensions": ["karbon"]
+ },
+ "application/vnd.kde.kchart": {
+ "source": "iana",
+ "extensions": ["chrt"]
+ },
+ "application/vnd.kde.kformula": {
+ "source": "iana",
+ "extensions": ["kfo"]
+ },
+ "application/vnd.kde.kivio": {
+ "source": "iana",
+ "extensions": ["flw"]
+ },
+ "application/vnd.kde.kontour": {
+ "source": "iana",
+ "extensions": ["kon"]
+ },
+ "application/vnd.kde.kpresenter": {
+ "source": "iana",
+ "extensions": ["kpr","kpt"]
+ },
+ "application/vnd.kde.kspread": {
+ "source": "iana",
+ "extensions": ["ksp"]
+ },
+ "application/vnd.kde.kword": {
+ "source": "iana",
+ "extensions": ["kwd","kwt"]
+ },
+ "application/vnd.kenameaapp": {
+ "source": "iana",
+ "extensions": ["htke"]
+ },
+ "application/vnd.kidspiration": {
+ "source": "iana",
+ "extensions": ["kia"]
+ },
+ "application/vnd.kinar": {
+ "source": "iana",
+ "extensions": ["kne","knp"]
+ },
+ "application/vnd.koan": {
+ "source": "iana",
+ "extensions": ["skp","skd","skt","skm"]
+ },
+ "application/vnd.kodak-descriptor": {
+ "source": "iana",
+ "extensions": ["sse"]
+ },
+ "application/vnd.las.las+xml": {
+ "source": "iana",
+ "extensions": ["lasxml"]
+ },
+ "application/vnd.liberty-request+xml": {
+ "source": "iana"
+ },
+ "application/vnd.llamagraphics.life-balance.desktop": {
+ "source": "iana",
+ "extensions": ["lbd"]
+ },
+ "application/vnd.llamagraphics.life-balance.exchange+xml": {
+ "source": "iana",
+ "extensions": ["lbe"]
+ },
+ "application/vnd.lotus-1-2-3": {
+ "source": "iana",
+ "extensions": ["123"]
+ },
+ "application/vnd.lotus-approach": {
+ "source": "iana",
+ "extensions": ["apr"]
+ },
+ "application/vnd.lotus-freelance": {
+ "source": "iana",
+ "extensions": ["pre"]
+ },
+ "application/vnd.lotus-notes": {
+ "source": "iana",
+ "extensions": ["nsf"]
+ },
+ "application/vnd.lotus-organizer": {
+ "source": "iana",
+ "extensions": ["org"]
+ },
+ "application/vnd.lotus-screencam": {
+ "source": "iana",
+ "extensions": ["scm"]
+ },
+ "application/vnd.lotus-wordpro": {
+ "source": "iana",
+ "extensions": ["lwp"]
+ },
+ "application/vnd.macports.portpkg": {
+ "source": "iana",
+ "extensions": ["portpkg"]
+ },
+ "application/vnd.marlin.drm.actiontoken+xml": {
+ "source": "iana"
+ },
+ "application/vnd.marlin.drm.conftoken+xml": {
+ "source": "iana"
+ },
+ "application/vnd.marlin.drm.license+xml": {
+ "source": "iana"
+ },
+ "application/vnd.marlin.drm.mdcf": {
+ "source": "iana"
+ },
+ "application/vnd.mason+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.maxmind.maxmind-db": {
+ "source": "iana"
+ },
+ "application/vnd.mcd": {
+ "source": "iana",
+ "extensions": ["mcd"]
+ },
+ "application/vnd.medcalcdata": {
+ "source": "iana",
+ "extensions": ["mc1"]
+ },
+ "application/vnd.mediastation.cdkey": {
+ "source": "iana",
+ "extensions": ["cdkey"]
+ },
+ "application/vnd.meridian-slingshot": {
+ "source": "iana"
+ },
+ "application/vnd.mfer": {
+ "source": "iana",
+ "extensions": ["mwf"]
+ },
+ "application/vnd.mfmp": {
+ "source": "iana",
+ "extensions": ["mfm"]
+ },
+ "application/vnd.micro+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.micrografx.flo": {
+ "source": "iana",
+ "extensions": ["flo"]
+ },
+ "application/vnd.micrografx.igx": {
+ "source": "iana",
+ "extensions": ["igx"]
+ },
+ "application/vnd.microsoft.portable-executable": {
+ "source": "iana"
+ },
+ "application/vnd.miele+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.mif": {
+ "source": "iana",
+ "extensions": ["mif"]
+ },
+ "application/vnd.minisoft-hp3000-save": {
+ "source": "iana"
+ },
+ "application/vnd.mitsubishi.misty-guard.trustweb": {
+ "source": "iana"
+ },
+ "application/vnd.mobius.daf": {
+ "source": "iana",
+ "extensions": ["daf"]
+ },
+ "application/vnd.mobius.dis": {
+ "source": "iana",
+ "extensions": ["dis"]
+ },
+ "application/vnd.mobius.mbk": {
+ "source": "iana",
+ "extensions": ["mbk"]
+ },
+ "application/vnd.mobius.mqy": {
+ "source": "iana",
+ "extensions": ["mqy"]
+ },
+ "application/vnd.mobius.msl": {
+ "source": "iana",
+ "extensions": ["msl"]
+ },
+ "application/vnd.mobius.plc": {
+ "source": "iana",
+ "extensions": ["plc"]
+ },
+ "application/vnd.mobius.txf": {
+ "source": "iana",
+ "extensions": ["txf"]
+ },
+ "application/vnd.mophun.application": {
+ "source": "iana",
+ "extensions": ["mpn"]
+ },
+ "application/vnd.mophun.certificate": {
+ "source": "iana",
+ "extensions": ["mpc"]
+ },
+ "application/vnd.motorola.flexsuite": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.adsi": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.fis": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.gotap": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.kmr": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.ttc": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.wem": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.iprm": {
+ "source": "iana"
+ },
+ "application/vnd.mozilla.xul+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xul"]
+ },
+ "application/vnd.ms-3mfdocument": {
+ "source": "iana"
+ },
+ "application/vnd.ms-artgalry": {
+ "source": "iana",
+ "extensions": ["cil"]
+ },
+ "application/vnd.ms-asf": {
+ "source": "iana"
+ },
+ "application/vnd.ms-cab-compressed": {
+ "source": "iana",
+ "extensions": ["cab"]
+ },
+ "application/vnd.ms-color.iccprofile": {
+ "source": "apache"
+ },
+ "application/vnd.ms-excel": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xls","xlm","xla","xlc","xlt","xlw"]
+ },
+ "application/vnd.ms-excel.addin.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlam"]
+ },
+ "application/vnd.ms-excel.sheet.binary.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlsb"]
+ },
+ "application/vnd.ms-excel.sheet.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlsm"]
+ },
+ "application/vnd.ms-excel.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xltm"]
+ },
+ "application/vnd.ms-fontobject": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["eot"]
+ },
+ "application/vnd.ms-htmlhelp": {
+ "source": "iana",
+ "extensions": ["chm"]
+ },
+ "application/vnd.ms-ims": {
+ "source": "iana",
+ "extensions": ["ims"]
+ },
+ "application/vnd.ms-lrm": {
+ "source": "iana",
+ "extensions": ["lrm"]
+ },
+ "application/vnd.ms-office.activex+xml": {
+ "source": "iana"
+ },
+ "application/vnd.ms-officetheme": {
+ "source": "iana",
+ "extensions": ["thmx"]
+ },
+ "application/vnd.ms-opentype": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.ms-package.obfuscated-opentype": {
+ "source": "apache"
+ },
+ "application/vnd.ms-pki.seccat": {
+ "source": "apache",
+ "extensions": ["cat"]
+ },
+ "application/vnd.ms-pki.stl": {
+ "source": "apache",
+ "extensions": ["stl"]
+ },
+ "application/vnd.ms-playready.initiator+xml": {
+ "source": "iana"
+ },
+ "application/vnd.ms-powerpoint": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ppt","pps","pot"]
+ },
+ "application/vnd.ms-powerpoint.addin.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["ppam"]
+ },
+ "application/vnd.ms-powerpoint.presentation.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["pptm"]
+ },
+ "application/vnd.ms-powerpoint.slide.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["sldm"]
+ },
+ "application/vnd.ms-powerpoint.slideshow.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["ppsm"]
+ },
+ "application/vnd.ms-powerpoint.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["potm"]
+ },
+ "application/vnd.ms-printing.printticket+xml": {
+ "source": "apache"
+ },
+ "application/vnd.ms-project": {
+ "source": "iana",
+ "extensions": ["mpp","mpt"]
+ },
+ "application/vnd.ms-tnef": {
+ "source": "iana"
+ },
+ "application/vnd.ms-windows.printerpairing": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.lic-chlg-req": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.lic-resp": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.meter-chlg-req": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.meter-resp": {
+ "source": "iana"
+ },
+ "application/vnd.ms-word.document.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["docm"]
+ },
+ "application/vnd.ms-word.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["dotm"]
+ },
+ "application/vnd.ms-works": {
+ "source": "iana",
+ "extensions": ["wps","wks","wcm","wdb"]
+ },
+ "application/vnd.ms-wpl": {
+ "source": "iana",
+ "extensions": ["wpl"]
+ },
+ "application/vnd.ms-xpsdocument": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xps"]
+ },
+ "application/vnd.msa-disk-image": {
+ "source": "iana"
+ },
+ "application/vnd.mseq": {
+ "source": "iana",
+ "extensions": ["mseq"]
+ },
+ "application/vnd.msign": {
+ "source": "iana"
+ },
+ "application/vnd.multiad.creator": {
+ "source": "iana"
+ },
+ "application/vnd.multiad.creator.cif": {
+ "source": "iana"
+ },
+ "application/vnd.music-niff": {
+ "source": "iana"
+ },
+ "application/vnd.musician": {
+ "source": "iana",
+ "extensions": ["mus"]
+ },
+ "application/vnd.muvee.style": {
+ "source": "iana",
+ "extensions": ["msty"]
+ },
+ "application/vnd.mynfc": {
+ "source": "iana",
+ "extensions": ["taglet"]
+ },
+ "application/vnd.ncd.control": {
+ "source": "iana"
+ },
+ "application/vnd.ncd.reference": {
+ "source": "iana"
+ },
+ "application/vnd.nervana": {
+ "source": "iana"
+ },
+ "application/vnd.netfpx": {
+ "source": "iana"
+ },
+ "application/vnd.neurolanguage.nlu": {
+ "source": "iana",
+ "extensions": ["nlu"]
+ },
+ "application/vnd.nintendo.nitro.rom": {
+ "source": "iana"
+ },
+ "application/vnd.nintendo.snes.rom": {
+ "source": "iana"
+ },
+ "application/vnd.nitf": {
+ "source": "iana",
+ "extensions": ["ntf","nitf"]
+ },
+ "application/vnd.noblenet-directory": {
+ "source": "iana",
+ "extensions": ["nnd"]
+ },
+ "application/vnd.noblenet-sealer": {
+ "source": "iana",
+ "extensions": ["nns"]
+ },
+ "application/vnd.noblenet-web": {
+ "source": "iana",
+ "extensions": ["nnw"]
+ },
+ "application/vnd.nokia.catalogs": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.conml+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.conml+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.iptv.config+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.isds-radio-presets": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.landmark+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.landmark+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.landmarkcollection+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.n-gage.ac+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.n-gage.data": {
+ "source": "iana",
+ "extensions": ["ngdat"]
+ },
+ "application/vnd.nokia.n-gage.symbian.install": {
+ "source": "iana",
+ "extensions": ["n-gage"]
+ },
+ "application/vnd.nokia.ncd": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.pcd+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.pcd+xml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.radio-preset": {
+ "source": "iana",
+ "extensions": ["rpst"]
+ },
+ "application/vnd.nokia.radio-presets": {
+ "source": "iana",
+ "extensions": ["rpss"]
+ },
+ "application/vnd.novadigm.edm": {
+ "source": "iana",
+ "extensions": ["edm"]
+ },
+ "application/vnd.novadigm.edx": {
+ "source": "iana",
+ "extensions": ["edx"]
+ },
+ "application/vnd.novadigm.ext": {
+ "source": "iana",
+ "extensions": ["ext"]
+ },
+ "application/vnd.ntt-local.content-share": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.file-transfer": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.ogw_remote-access": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.sip-ta_remote": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.sip-ta_tcp_stream": {
+ "source": "iana"
+ },
+ "application/vnd.oasis.opendocument.chart": {
+ "source": "iana",
+ "extensions": ["odc"]
+ },
+ "application/vnd.oasis.opendocument.chart-template": {
+ "source": "iana",
+ "extensions": ["otc"]
+ },
+ "application/vnd.oasis.opendocument.database": {
+ "source": "iana",
+ "extensions": ["odb"]
+ },
+ "application/vnd.oasis.opendocument.formula": {
+ "source": "iana",
+ "extensions": ["odf"]
+ },
+ "application/vnd.oasis.opendocument.formula-template": {
+ "source": "iana",
+ "extensions": ["odft"]
+ },
+ "application/vnd.oasis.opendocument.graphics": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odg"]
+ },
+ "application/vnd.oasis.opendocument.graphics-template": {
+ "source": "iana",
+ "extensions": ["otg"]
+ },
+ "application/vnd.oasis.opendocument.image": {
+ "source": "iana",
+ "extensions": ["odi"]
+ },
+ "application/vnd.oasis.opendocument.image-template": {
+ "source": "iana",
+ "extensions": ["oti"]
+ },
+ "application/vnd.oasis.opendocument.presentation": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odp"]
+ },
+ "application/vnd.oasis.opendocument.presentation-template": {
+ "source": "iana",
+ "extensions": ["otp"]
+ },
+ "application/vnd.oasis.opendocument.spreadsheet": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ods"]
+ },
+ "application/vnd.oasis.opendocument.spreadsheet-template": {
+ "source": "iana",
+ "extensions": ["ots"]
+ },
+ "application/vnd.oasis.opendocument.text": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odt"]
+ },
+ "application/vnd.oasis.opendocument.text-master": {
+ "source": "iana",
+ "extensions": ["odm"]
+ },
+ "application/vnd.oasis.opendocument.text-template": {
+ "source": "iana",
+ "extensions": ["ott"]
+ },
+ "application/vnd.oasis.opendocument.text-web": {
+ "source": "iana",
+ "extensions": ["oth"]
+ },
+ "application/vnd.obn": {
+ "source": "iana"
+ },
+ "application/vnd.oftn.l10n+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.contentaccessdownload+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.contentaccessstreaming+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.cspg-hexbinary": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.dae.svg+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.dae.xhtml+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.mippvcontrolmessage+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.pae.gem": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.spdiscovery+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.spdlist+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.ueprofile+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.userprofile+xml": {
+ "source": "iana"
+ },
+ "application/vnd.olpc-sugar": {
+ "source": "iana",
+ "extensions": ["xo"]
+ },
+ "application/vnd.oma-scws-config": {
+ "source": "iana"
+ },
+ "application/vnd.oma-scws-http-request": {
+ "source": "iana"
+ },
+ "application/vnd.oma-scws-http-response": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.associated-procedure-parameter+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.drm-trigger+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.imd+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.ltkm": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.notification+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.provisioningtrigger": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sgboot": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sgdd+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sgdu": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.simple-symbol-container": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.smartcard-trigger+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sprov+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.stkm": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-address-book+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-feature-handler+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-pcc+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-subs-invite+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-user-prefs+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.dcd": {
+ "source": "iana"
+ },
+ "application/vnd.oma.dcdc": {
+ "source": "iana"
+ },
+ "application/vnd.oma.dd2+xml": {
+ "source": "iana",
+ "extensions": ["dd2"]
+ },
+ "application/vnd.oma.drm.risd+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.group-usage-list+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.pal+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.poc.detailed-progress-report+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.poc.final-report+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.poc.groups+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.poc.invocation-descriptor+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.poc.optimized-progress-report+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.push": {
+ "source": "iana"
+ },
+ "application/vnd.oma.scidm.messages+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oma.xcap-directory+xml": {
+ "source": "iana"
+ },
+ "application/vnd.omads-email+xml": {
+ "source": "iana"
+ },
+ "application/vnd.omads-file+xml": {
+ "source": "iana"
+ },
+ "application/vnd.omads-folder+xml": {
+ "source": "iana"
+ },
+ "application/vnd.omaloc-supl-init": {
+ "source": "iana"
+ },
+ "application/vnd.openeye.oeb": {
+ "source": "iana"
+ },
+ "application/vnd.openofficeorg.extension": {
+ "source": "apache",
+ "extensions": ["oxt"]
+ },
+ "application/vnd.openxmlformats-officedocument.custom-properties+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.customxmlproperties+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawing+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.extended-properties+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml-template": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.comments+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pptx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presprops+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slide": {
+ "source": "iana",
+ "extensions": ["sldx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slide+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow": {
+ "source": "iana",
+ "extensions": ["ppsx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.tags+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.template": {
+ "source": "apache",
+ "extensions": ["potx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml-template": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xlsx"]
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.template": {
+ "source": "apache",
+ "extensions": ["xltx"]
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.theme+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.themeoverride+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.vmldrawing": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml-template": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["docx"]
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template": {
+ "source": "apache",
+ "extensions": ["dotx"]
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-package.core-properties+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-package.relationships+xml": {
+ "source": "iana"
+ },
+ "application/vnd.oracle.resource+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.orange.indata": {
+ "source": "iana"
+ },
+ "application/vnd.osa.netdeploy": {
+ "source": "iana"
+ },
+ "application/vnd.osgeo.mapguide.package": {
+ "source": "iana",
+ "extensions": ["mgp"]
+ },
+ "application/vnd.osgi.bundle": {
+ "source": "iana"
+ },
+ "application/vnd.osgi.dp": {
+ "source": "iana",
+ "extensions": ["dp"]
+ },
+ "application/vnd.osgi.subsystem": {
+ "source": "iana",
+ "extensions": ["esa"]
+ },
+ "application/vnd.otps.ct-kip+xml": {
+ "source": "iana"
+ },
+ "application/vnd.palm": {
+ "source": "iana",
+ "extensions": ["pdb","pqa","oprc"]
+ },
+ "application/vnd.panoply": {
+ "source": "iana"
+ },
+ "application/vnd.paos+xml": {
+ "source": "iana"
+ },
+ "application/vnd.paos.xml": {
+ "source": "apache"
+ },
+ "application/vnd.pawaafile": {
+ "source": "iana",
+ "extensions": ["paw"]
+ },
+ "application/vnd.pcos": {
+ "source": "iana"
+ },
+ "application/vnd.pg.format": {
+ "source": "iana",
+ "extensions": ["str"]
+ },
+ "application/vnd.pg.osasli": {
+ "source": "iana",
+ "extensions": ["ei6"]
+ },
+ "application/vnd.piaccess.application-licence": {
+ "source": "iana"
+ },
+ "application/vnd.picsel": {
+ "source": "iana",
+ "extensions": ["efif"]
+ },
+ "application/vnd.pmi.widget": {
+ "source": "iana",
+ "extensions": ["wg"]
+ },
+ "application/vnd.poc.group-advertisement+xml": {
+ "source": "iana"
+ },
+ "application/vnd.pocketlearn": {
+ "source": "iana",
+ "extensions": ["plf"]
+ },
+ "application/vnd.powerbuilder6": {
+ "source": "iana",
+ "extensions": ["pbd"]
+ },
+ "application/vnd.powerbuilder6-s": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder7": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder7-s": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder75": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder75-s": {
+ "source": "iana"
+ },
+ "application/vnd.preminet": {
+ "source": "iana"
+ },
+ "application/vnd.previewsystems.box": {
+ "source": "iana",
+ "extensions": ["box"]
+ },
+ "application/vnd.proteus.magazine": {
+ "source": "iana",
+ "extensions": ["mgz"]
+ },
+ "application/vnd.publishare-delta-tree": {
+ "source": "iana",
+ "extensions": ["qps"]
+ },
+ "application/vnd.pvi.ptid1": {
+ "source": "iana",
+ "extensions": ["ptid"]
+ },
+ "application/vnd.pwg-multiplexed": {
+ "source": "iana"
+ },
+ "application/vnd.pwg-xhtml-print+xml": {
+ "source": "iana"
+ },
+ "application/vnd.qualcomm.brew-app-res": {
+ "source": "iana"
+ },
+ "application/vnd.quark.quarkxpress": {
+ "source": "iana",
+ "extensions": ["qxd","qxt","qwd","qwt","qxl","qxb"]
+ },
+ "application/vnd.quobject-quoxdocument": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.moml+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-audit+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-audit-conf+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-audit-conn+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-audit-dialog+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-audit-stream+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-conf+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-base+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-fax-detect+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-fax-sendrecv+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-group+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-speech+xml": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.msml-dialog-transform+xml": {
+ "source": "iana"
+ },
+ "application/vnd.rainstor.data": {
+ "source": "iana"
+ },
+ "application/vnd.rapid": {
+ "source": "iana"
+ },
+ "application/vnd.realvnc.bed": {
+ "source": "iana",
+ "extensions": ["bed"]
+ },
+ "application/vnd.recordare.musicxml": {
+ "source": "iana",
+ "extensions": ["mxl"]
+ },
+ "application/vnd.recordare.musicxml+xml": {
+ "source": "iana",
+ "extensions": ["musicxml"]
+ },
+ "application/vnd.renlearn.rlprint": {
+ "source": "iana"
+ },
+ "application/vnd.rig.cryptonote": {
+ "source": "iana",
+ "extensions": ["cryptonote"]
+ },
+ "application/vnd.rim.cod": {
+ "source": "apache",
+ "extensions": ["cod"]
+ },
+ "application/vnd.rn-realmedia": {
+ "source": "apache",
+ "extensions": ["rm"]
+ },
+ "application/vnd.rn-realmedia-vbr": {
+ "source": "apache",
+ "extensions": ["rmvb"]
+ },
+ "application/vnd.route66.link66+xml": {
+ "source": "iana",
+ "extensions": ["link66"]
+ },
+ "application/vnd.rs-274x": {
+ "source": "iana"
+ },
+ "application/vnd.ruckus.download": {
+ "source": "iana"
+ },
+ "application/vnd.s3sms": {
+ "source": "iana"
+ },
+ "application/vnd.sailingtracker.track": {
+ "source": "iana",
+ "extensions": ["st"]
+ },
+ "application/vnd.sbm.cid": {
+ "source": "iana"
+ },
+ "application/vnd.sbm.mid2": {
+ "source": "iana"
+ },
+ "application/vnd.scribus": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.3df": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.csf": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.doc": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.eml": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.mht": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.net": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.ppt": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.tiff": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.xls": {
+ "source": "iana"
+ },
+ "application/vnd.sealedmedia.softseal.html": {
+ "source": "iana"
+ },
+ "application/vnd.sealedmedia.softseal.pdf": {
+ "source": "iana"
+ },
+ "application/vnd.seemail": {
+ "source": "iana",
+ "extensions": ["see"]
+ },
+ "application/vnd.sema": {
+ "source": "iana",
+ "extensions": ["sema"]
+ },
+ "application/vnd.semd": {
+ "source": "iana",
+ "extensions": ["semd"]
+ },
+ "application/vnd.semf": {
+ "source": "iana",
+ "extensions": ["semf"]
+ },
+ "application/vnd.shana.informed.formdata": {
+ "source": "iana",
+ "extensions": ["ifm"]
+ },
+ "application/vnd.shana.informed.formtemplate": {
+ "source": "iana",
+ "extensions": ["itp"]
+ },
+ "application/vnd.shana.informed.interchange": {
+ "source": "iana",
+ "extensions": ["iif"]
+ },
+ "application/vnd.shana.informed.package": {
+ "source": "iana",
+ "extensions": ["ipk"]
+ },
+ "application/vnd.simtech-mindmapper": {
+ "source": "iana",
+ "extensions": ["twd","twds"]
+ },
+ "application/vnd.siren+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.smaf": {
+ "source": "iana",
+ "extensions": ["mmf"]
+ },
+ "application/vnd.smart.notebook": {
+ "source": "iana"
+ },
+ "application/vnd.smart.teacher": {
+ "source": "iana",
+ "extensions": ["teacher"]
+ },
+ "application/vnd.software602.filler.form+xml": {
+ "source": "iana"
+ },
+ "application/vnd.software602.filler.form-xml-zip": {
+ "source": "iana"
+ },
+ "application/vnd.solent.sdkm+xml": {
+ "source": "iana",
+ "extensions": ["sdkm","sdkd"]
+ },
+ "application/vnd.spotfire.dxp": {
+ "source": "iana",
+ "extensions": ["dxp"]
+ },
+ "application/vnd.spotfire.sfs": {
+ "source": "iana",
+ "extensions": ["sfs"]
+ },
+ "application/vnd.sss-cod": {
+ "source": "iana"
+ },
+ "application/vnd.sss-dtf": {
+ "source": "iana"
+ },
+ "application/vnd.sss-ntf": {
+ "source": "iana"
+ },
+ "application/vnd.stardivision.calc": {
+ "source": "apache",
+ "extensions": ["sdc"]
+ },
+ "application/vnd.stardivision.draw": {
+ "source": "apache",
+ "extensions": ["sda"]
+ },
+ "application/vnd.stardivision.impress": {
+ "source": "apache",
+ "extensions": ["sdd"]
+ },
+ "application/vnd.stardivision.math": {
+ "source": "apache",
+ "extensions": ["smf"]
+ },
+ "application/vnd.stardivision.writer": {
+ "source": "apache",
+ "extensions": ["sdw","vor"]
+ },
+ "application/vnd.stardivision.writer-global": {
+ "source": "apache",
+ "extensions": ["sgl"]
+ },
+ "application/vnd.stepmania.package": {
+ "source": "iana",
+ "extensions": ["smzip"]
+ },
+ "application/vnd.stepmania.stepchart": {
+ "source": "iana",
+ "extensions": ["sm"]
+ },
+ "application/vnd.street-stream": {
+ "source": "iana"
+ },
+ "application/vnd.sun.wadl+xml": {
+ "source": "iana"
+ },
+ "application/vnd.sun.xml.calc": {
+ "source": "apache",
+ "extensions": ["sxc"]
+ },
+ "application/vnd.sun.xml.calc.template": {
+ "source": "apache",
+ "extensions": ["stc"]
+ },
+ "application/vnd.sun.xml.draw": {
+ "source": "apache",
+ "extensions": ["sxd"]
+ },
+ "application/vnd.sun.xml.draw.template": {
+ "source": "apache",
+ "extensions": ["std"]
+ },
+ "application/vnd.sun.xml.impress": {
+ "source": "apache",
+ "extensions": ["sxi"]
+ },
+ "application/vnd.sun.xml.impress.template": {
+ "source": "apache",
+ "extensions": ["sti"]
+ },
+ "application/vnd.sun.xml.math": {
+ "source": "apache",
+ "extensions": ["sxm"]
+ },
+ "application/vnd.sun.xml.writer": {
+ "source": "apache",
+ "extensions": ["sxw"]
+ },
+ "application/vnd.sun.xml.writer.global": {
+ "source": "apache",
+ "extensions": ["sxg"]
+ },
+ "application/vnd.sun.xml.writer.template": {
+ "source": "apache",
+ "extensions": ["stw"]
+ },
+ "application/vnd.sus-calendar": {
+ "source": "iana",
+ "extensions": ["sus","susp"]
+ },
+ "application/vnd.svd": {
+ "source": "iana",
+ "extensions": ["svd"]
+ },
+ "application/vnd.swiftview-ics": {
+ "source": "iana"
+ },
+ "application/vnd.symbian.install": {
+ "source": "apache",
+ "extensions": ["sis","sisx"]
+ },
+ "application/vnd.syncml+xml": {
+ "source": "iana",
+ "extensions": ["xsm"]
+ },
+ "application/vnd.syncml.dm+wbxml": {
+ "source": "iana",
+ "extensions": ["bdm"]
+ },
+ "application/vnd.syncml.dm+xml": {
+ "source": "iana",
+ "extensions": ["xdm"]
+ },
+ "application/vnd.syncml.dm.notification": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmddf+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmddf+xml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmtnds+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmtnds+xml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.ds.notification": {
+ "source": "iana"
+ },
+ "application/vnd.tao.intent-module-archive": {
+ "source": "iana",
+ "extensions": ["tao"]
+ },
+ "application/vnd.tcpdump.pcap": {
+ "source": "iana",
+ "extensions": ["pcap","cap","dmp"]
+ },
+ "application/vnd.tmd.mediaflex.api+xml": {
+ "source": "iana"
+ },
+ "application/vnd.tmobile-livetv": {
+ "source": "iana",
+ "extensions": ["tmo"]
+ },
+ "application/vnd.trid.tpt": {
+ "source": "iana",
+ "extensions": ["tpt"]
+ },
+ "application/vnd.triscape.mxs": {
+ "source": "iana",
+ "extensions": ["mxs"]
+ },
+ "application/vnd.trueapp": {
+ "source": "iana",
+ "extensions": ["tra"]
+ },
+ "application/vnd.truedoc": {
+ "source": "iana"
+ },
+ "application/vnd.ubisoft.webplayer": {
+ "source": "iana"
+ },
+ "application/vnd.ufdl": {
+ "source": "iana",
+ "extensions": ["ufd","ufdl"]
+ },
+ "application/vnd.uiq.theme": {
+ "source": "iana",
+ "extensions": ["utz"]
+ },
+ "application/vnd.umajin": {
+ "source": "iana",
+ "extensions": ["umj"]
+ },
+ "application/vnd.unity": {
+ "source": "iana",
+ "extensions": ["unityweb"]
+ },
+ "application/vnd.uoml+xml": {
+ "source": "iana",
+ "extensions": ["uoml"]
+ },
+ "application/vnd.uplanet.alert": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.alert-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.bearer-choice": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.bearer-choice-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.cacheop": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.cacheop-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.channel": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.channel-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.list": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.list-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.listcmd": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.listcmd-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.signal": {
+ "source": "iana"
+ },
+ "application/vnd.valve.source.material": {
+ "source": "iana"
+ },
+ "application/vnd.vcx": {
+ "source": "iana",
+ "extensions": ["vcx"]
+ },
+ "application/vnd.vd-study": {
+ "source": "iana"
+ },
+ "application/vnd.vectorworks": {
+ "source": "iana"
+ },
+ "application/vnd.verimatrix.vcas": {
+ "source": "iana"
+ },
+ "application/vnd.vidsoft.vidconference": {
+ "source": "iana"
+ },
+ "application/vnd.visio": {
+ "source": "iana",
+ "extensions": ["vsd","vst","vss","vsw"]
+ },
+ "application/vnd.visionary": {
+ "source": "iana",
+ "extensions": ["vis"]
+ },
+ "application/vnd.vividence.scriptfile": {
+ "source": "iana"
+ },
+ "application/vnd.vsf": {
+ "source": "iana",
+ "extensions": ["vsf"]
+ },
+ "application/vnd.wap.sic": {
+ "source": "iana"
+ },
+ "application/vnd.wap.slc": {
+ "source": "iana"
+ },
+ "application/vnd.wap.wbxml": {
+ "source": "iana",
+ "extensions": ["wbxml"]
+ },
+ "application/vnd.wap.wmlc": {
+ "source": "iana",
+ "extensions": ["wmlc"]
+ },
+ "application/vnd.wap.wmlscriptc": {
+ "source": "iana",
+ "extensions": ["wmlsc"]
+ },
+ "application/vnd.webturbo": {
+ "source": "iana",
+ "extensions": ["wtb"]
+ },
+ "application/vnd.wfa.p2p": {
+ "source": "iana"
+ },
+ "application/vnd.wfa.wsc": {
+ "source": "iana"
+ },
+ "application/vnd.windows.devicepairing": {
+ "source": "iana"
+ },
+ "application/vnd.wmc": {
+ "source": "iana"
+ },
+ "application/vnd.wmf.bootstrap": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.mathematica": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.mathematica.package": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.player": {
+ "source": "iana",
+ "extensions": ["nbp"]
+ },
+ "application/vnd.wordperfect": {
+ "source": "iana",
+ "extensions": ["wpd"]
+ },
+ "application/vnd.wqd": {
+ "source": "iana",
+ "extensions": ["wqd"]
+ },
+ "application/vnd.wrq-hp3000-labelled": {
+ "source": "iana"
+ },
+ "application/vnd.wt.stf": {
+ "source": "iana",
+ "extensions": ["stf"]
+ },
+ "application/vnd.wv.csp+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.wv.csp+xml": {
+ "source": "iana"
+ },
+ "application/vnd.wv.ssp+xml": {
+ "source": "iana"
+ },
+ "application/vnd.xacml+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.xara": {
+ "source": "iana",
+ "extensions": ["xar"]
+ },
+ "application/vnd.xfdl": {
+ "source": "iana",
+ "extensions": ["xfdl"]
+ },
+ "application/vnd.xfdl.webform": {
+ "source": "iana"
+ },
+ "application/vnd.xmi+xml": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.cpkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.dpkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.plan": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.ppkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.xlim": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.hv-dic": {
+ "source": "iana",
+ "extensions": ["hvd"]
+ },
+ "application/vnd.yamaha.hv-script": {
+ "source": "iana",
+ "extensions": ["hvs"]
+ },
+ "application/vnd.yamaha.hv-voice": {
+ "source": "iana",
+ "extensions": ["hvp"]
+ },
+ "application/vnd.yamaha.openscoreformat": {
+ "source": "iana",
+ "extensions": ["osf"]
+ },
+ "application/vnd.yamaha.openscoreformat.osfpvg+xml": {
+ "source": "iana",
+ "extensions": ["osfpvg"]
+ },
+ "application/vnd.yamaha.remote-setup": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.smaf-audio": {
+ "source": "iana",
+ "extensions": ["saf"]
+ },
+ "application/vnd.yamaha.smaf-phrase": {
+ "source": "iana",
+ "extensions": ["spf"]
+ },
+ "application/vnd.yamaha.through-ngn": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.tunnel-udpencap": {
+ "source": "iana"
+ },
+ "application/vnd.yaoweme": {
+ "source": "iana"
+ },
+ "application/vnd.yellowriver-custom-menu": {
+ "source": "iana",
+ "extensions": ["cmp"]
+ },
+ "application/vnd.zul": {
+ "source": "iana",
+ "extensions": ["zir","zirz"]
+ },
+ "application/vnd.zzazz.deck+xml": {
+ "source": "iana",
+ "extensions": ["zaz"]
+ },
+ "application/voicexml+xml": {
+ "source": "iana",
+ "extensions": ["vxml"]
+ },
+ "application/vq-rtcpxr": {
+ "source": "iana"
+ },
+ "application/watcherinfo+xml": {
+ "source": "iana"
+ },
+ "application/whoispp-query": {
+ "source": "iana"
+ },
+ "application/whoispp-response": {
+ "source": "iana"
+ },
+ "application/widget": {
+ "source": "iana",
+ "extensions": ["wgt"]
+ },
+ "application/winhlp": {
+ "source": "apache",
+ "extensions": ["hlp"]
+ },
+ "application/wita": {
+ "source": "iana"
+ },
+ "application/wordperfect5.1": {
+ "source": "iana"
+ },
+ "application/wsdl+xml": {
+ "source": "iana",
+ "extensions": ["wsdl"]
+ },
+ "application/wspolicy+xml": {
+ "source": "iana",
+ "extensions": ["wspolicy"]
+ },
+ "application/x-7z-compressed": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["7z"]
+ },
+ "application/x-abiword": {
+ "source": "apache",
+ "extensions": ["abw"]
+ },
+ "application/x-ace-compressed": {
+ "source": "apache",
+ "extensions": ["ace"]
+ },
+ "application/x-amf": {
+ "source": "apache"
+ },
+ "application/x-apple-diskimage": {
+ "source": "apache",
+ "extensions": ["dmg"]
+ },
+ "application/x-authorware-bin": {
+ "source": "apache",
+ "extensions": ["aab","x32","u32","vox"]
+ },
+ "application/x-authorware-map": {
+ "source": "apache",
+ "extensions": ["aam"]
+ },
+ "application/x-authorware-seg": {
+ "source": "apache",
+ "extensions": ["aas"]
+ },
+ "application/x-bcpio": {
+ "source": "apache",
+ "extensions": ["bcpio"]
+ },
+ "application/x-bdoc": {
+ "compressible": false,
+ "extensions": ["bdoc"]
+ },
+ "application/x-bittorrent": {
+ "source": "apache",
+ "extensions": ["torrent"]
+ },
+ "application/x-blorb": {
+ "source": "apache",
+ "extensions": ["blb","blorb"]
+ },
+ "application/x-bzip": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["bz"]
+ },
+ "application/x-bzip2": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["bz2","boz"]
+ },
+ "application/x-cbr": {
+ "source": "apache",
+ "extensions": ["cbr","cba","cbt","cbz","cb7"]
+ },
+ "application/x-cdlink": {
+ "source": "apache",
+ "extensions": ["vcd"]
+ },
+ "application/x-cfs-compressed": {
+ "source": "apache",
+ "extensions": ["cfs"]
+ },
+ "application/x-chat": {
+ "source": "apache",
+ "extensions": ["chat"]
+ },
+ "application/x-chess-pgn": {
+ "source": "apache",
+ "extensions": ["pgn"]
+ },
+ "application/x-chrome-extension": {
+ "extensions": ["crx"]
+ },
+ "application/x-cocoa": {
+ "source": "nginx",
+ "extensions": ["cco"]
+ },
+ "application/x-compress": {
+ "source": "apache"
+ },
+ "application/x-conference": {
+ "source": "apache",
+ "extensions": ["nsc"]
+ },
+ "application/x-cpio": {
+ "source": "apache",
+ "extensions": ["cpio"]
+ },
+ "application/x-csh": {
+ "source": "apache",
+ "extensions": ["csh"]
+ },
+ "application/x-deb": {
+ "compressible": false
+ },
+ "application/x-debian-package": {
+ "source": "apache",
+ "extensions": ["deb","udeb"]
+ },
+ "application/x-dgc-compressed": {
+ "source": "apache",
+ "extensions": ["dgc"]
+ },
+ "application/x-director": {
+ "source": "apache",
+ "extensions": ["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]
+ },
+ "application/x-doom": {
+ "source": "apache",
+ "extensions": ["wad"]
+ },
+ "application/x-dtbncx+xml": {
+ "source": "apache",
+ "extensions": ["ncx"]
+ },
+ "application/x-dtbook+xml": {
+ "source": "apache",
+ "extensions": ["dtb"]
+ },
+ "application/x-dtbresource+xml": {
+ "source": "apache",
+ "extensions": ["res"]
+ },
+ "application/x-dvi": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["dvi"]
+ },
+ "application/x-envoy": {
+ "source": "apache",
+ "extensions": ["evy"]
+ },
+ "application/x-eva": {
+ "source": "apache",
+ "extensions": ["eva"]
+ },
+ "application/x-font-bdf": {
+ "source": "apache",
+ "extensions": ["bdf"]
+ },
+ "application/x-font-dos": {
+ "source": "apache"
+ },
+ "application/x-font-framemaker": {
+ "source": "apache"
+ },
+ "application/x-font-ghostscript": {
+ "source": "apache",
+ "extensions": ["gsf"]
+ },
+ "application/x-font-libgrx": {
+ "source": "apache"
+ },
+ "application/x-font-linux-psf": {
+ "source": "apache",
+ "extensions": ["psf"]
+ },
+ "application/x-font-otf": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["otf"]
+ },
+ "application/x-font-pcf": {
+ "source": "apache",
+ "extensions": ["pcf"]
+ },
+ "application/x-font-snf": {
+ "source": "apache",
+ "extensions": ["snf"]
+ },
+ "application/x-font-speedo": {
+ "source": "apache"
+ },
+ "application/x-font-sunos-news": {
+ "source": "apache"
+ },
+ "application/x-font-ttf": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ttf","ttc"]
+ },
+ "application/x-font-type1": {
+ "source": "apache",
+ "extensions": ["pfa","pfb","pfm","afm"]
+ },
+ "application/x-font-vfont": {
+ "source": "apache"
+ },
+ "application/x-freearc": {
+ "source": "apache",
+ "extensions": ["arc"]
+ },
+ "application/x-futuresplash": {
+ "source": "apache",
+ "extensions": ["spl"]
+ },
+ "application/x-gca-compressed": {
+ "source": "apache",
+ "extensions": ["gca"]
+ },
+ "application/x-glulx": {
+ "source": "apache",
+ "extensions": ["ulx"]
+ },
+ "application/x-gnumeric": {
+ "source": "apache",
+ "extensions": ["gnumeric"]
+ },
+ "application/x-gramps-xml": {
+ "source": "apache",
+ "extensions": ["gramps"]
+ },
+ "application/x-gtar": {
+ "source": "apache",
+ "extensions": ["gtar"]
+ },
+ "application/x-gzip": {
+ "source": "apache"
+ },
+ "application/x-hdf": {
+ "source": "apache",
+ "extensions": ["hdf"]
+ },
+ "application/x-httpd-php": {
+ "compressible": true,
+ "extensions": ["php"]
+ },
+ "application/x-install-instructions": {
+ "source": "apache",
+ "extensions": ["install"]
+ },
+ "application/x-iso9660-image": {
+ "source": "apache",
+ "extensions": ["iso"]
+ },
+ "application/x-java-archive-diff": {
+ "source": "nginx",
+ "extensions": ["jardiff"]
+ },
+ "application/x-java-jnlp-file": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["jnlp"]
+ },
+ "application/x-javascript": {
+ "compressible": true
+ },
+ "application/x-latex": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["latex"]
+ },
+ "application/x-lua-bytecode": {
+ "extensions": ["luac"]
+ },
+ "application/x-lzh-compressed": {
+ "source": "apache",
+ "extensions": ["lzh","lha"]
+ },
+ "application/x-makeself": {
+ "source": "nginx",
+ "extensions": ["run"]
+ },
+ "application/x-mie": {
+ "source": "apache",
+ "extensions": ["mie"]
+ },
+ "application/x-mobipocket-ebook": {
+ "source": "apache",
+ "extensions": ["prc","mobi"]
+ },
+ "application/x-mpegurl": {
+ "compressible": false
+ },
+ "application/x-ms-application": {
+ "source": "apache",
+ "extensions": ["application"]
+ },
+ "application/x-ms-shortcut": {
+ "source": "apache",
+ "extensions": ["lnk"]
+ },
+ "application/x-ms-wmd": {
+ "source": "apache",
+ "extensions": ["wmd"]
+ },
+ "application/x-ms-wmz": {
+ "source": "apache",
+ "extensions": ["wmz"]
+ },
+ "application/x-ms-xbap": {
+ "source": "apache",
+ "extensions": ["xbap"]
+ },
+ "application/x-msaccess": {
+ "source": "apache",
+ "extensions": ["mdb"]
+ },
+ "application/x-msbinder": {
+ "source": "apache",
+ "extensions": ["obd"]
+ },
+ "application/x-mscardfile": {
+ "source": "apache",
+ "extensions": ["crd"]
+ },
+ "application/x-msclip": {
+ "source": "apache",
+ "extensions": ["clp"]
+ },
+ "application/x-msdownload": {
+ "source": "apache",
+ "extensions": ["exe","dll","com","bat","msi"]
+ },
+ "application/x-msmediaview": {
+ "source": "apache",
+ "extensions": ["mvb","m13","m14"]
+ },
+ "application/x-msmetafile": {
+ "source": "apache",
+ "extensions": ["wmf","wmz","emf","emz"]
+ },
+ "application/x-msmoney": {
+ "source": "apache",
+ "extensions": ["mny"]
+ },
+ "application/x-mspublisher": {
+ "source": "apache",
+ "extensions": ["pub"]
+ },
+ "application/x-msschedule": {
+ "source": "apache",
+ "extensions": ["scd"]
+ },
+ "application/x-msterminal": {
+ "source": "apache",
+ "extensions": ["trm"]
+ },
+ "application/x-mswrite": {
+ "source": "apache",
+ "extensions": ["wri"]
+ },
+ "application/x-netcdf": {
+ "source": "apache",
+ "extensions": ["nc","cdf"]
+ },
+ "application/x-ns-proxy-autoconfig": {
+ "compressible": true,
+ "extensions": ["pac"]
+ },
+ "application/x-nzb": {
+ "source": "apache",
+ "extensions": ["nzb"]
+ },
+ "application/x-perl": {
+ "source": "nginx",
+ "extensions": ["pl","pm"]
+ },
+ "application/x-pilot": {
+ "source": "nginx",
+ "extensions": ["prc","pdb"]
+ },
+ "application/x-pkcs12": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["p12","pfx"]
+ },
+ "application/x-pkcs7-certificates": {
+ "source": "apache",
+ "extensions": ["p7b","spc"]
+ },
+ "application/x-pkcs7-certreqresp": {
+ "source": "apache",
+ "extensions": ["p7r"]
+ },
+ "application/x-rar-compressed": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["rar"]
+ },
+ "application/x-redhat-package-manager": {
+ "source": "nginx",
+ "extensions": ["rpm"]
+ },
+ "application/x-research-info-systems": {
+ "source": "apache",
+ "extensions": ["ris"]
+ },
+ "application/x-sea": {
+ "source": "nginx",
+ "extensions": ["sea"]
+ },
+ "application/x-sh": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["sh"]
+ },
+ "application/x-shar": {
+ "source": "apache",
+ "extensions": ["shar"]
+ },
+ "application/x-shockwave-flash": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["swf"]
+ },
+ "application/x-silverlight-app": {
+ "source": "apache",
+ "extensions": ["xap"]
+ },
+ "application/x-sql": {
+ "source": "apache",
+ "extensions": ["sql"]
+ },
+ "application/x-stuffit": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["sit"]
+ },
+ "application/x-stuffitx": {
+ "source": "apache",
+ "extensions": ["sitx"]
+ },
+ "application/x-subrip": {
+ "source": "apache",
+ "extensions": ["srt"]
+ },
+ "application/x-sv4cpio": {
+ "source": "apache",
+ "extensions": ["sv4cpio"]
+ },
+ "application/x-sv4crc": {
+ "source": "apache",
+ "extensions": ["sv4crc"]
+ },
+ "application/x-t3vm-image": {
+ "source": "apache",
+ "extensions": ["t3"]
+ },
+ "application/x-tads": {
+ "source": "apache",
+ "extensions": ["gam"]
+ },
+ "application/x-tar": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["tar"]
+ },
+ "application/x-tcl": {
+ "source": "apache",
+ "extensions": ["tcl","tk"]
+ },
+ "application/x-tex": {
+ "source": "apache",
+ "extensions": ["tex"]
+ },
+ "application/x-tex-tfm": {
+ "source": "apache",
+ "extensions": ["tfm"]
+ },
+ "application/x-texinfo": {
+ "source": "apache",
+ "extensions": ["texinfo","texi"]
+ },
+ "application/x-tgif": {
+ "source": "apache",
+ "extensions": ["obj"]
+ },
+ "application/x-ustar": {
+ "source": "apache",
+ "extensions": ["ustar"]
+ },
+ "application/x-wais-source": {
+ "source": "apache",
+ "extensions": ["src"]
+ },
+ "application/x-web-app-manifest+json": {
+ "compressible": true,
+ "extensions": ["webapp"]
+ },
+ "application/x-www-form-urlencoded": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/x-x509-ca-cert": {
+ "source": "apache",
+ "extensions": ["der","crt","pem"]
+ },
+ "application/x-xfig": {
+ "source": "apache",
+ "extensions": ["fig"]
+ },
+ "application/x-xliff+xml": {
+ "source": "apache",
+ "extensions": ["xlf"]
+ },
+ "application/x-xpinstall": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["xpi"]
+ },
+ "application/x-xz": {
+ "source": "apache",
+ "extensions": ["xz"]
+ },
+ "application/x-zmachine": {
+ "source": "apache",
+ "extensions": ["z1","z2","z3","z4","z5","z6","z7","z8"]
+ },
+ "application/x400-bp": {
+ "source": "iana"
+ },
+ "application/xacml+xml": {
+ "source": "iana"
+ },
+ "application/xaml+xml": {
+ "source": "apache",
+ "extensions": ["xaml"]
+ },
+ "application/xcap-att+xml": {
+ "source": "iana"
+ },
+ "application/xcap-caps+xml": {
+ "source": "iana"
+ },
+ "application/xcap-diff+xml": {
+ "source": "iana",
+ "extensions": ["xdf"]
+ },
+ "application/xcap-el+xml": {
+ "source": "iana"
+ },
+ "application/xcap-error+xml": {
+ "source": "iana"
+ },
+ "application/xcap-ns+xml": {
+ "source": "iana"
+ },
+ "application/xcon-conference-info+xml": {
+ "source": "iana"
+ },
+ "application/xcon-conference-info-diff+xml": {
+ "source": "iana"
+ },
+ "application/xenc+xml": {
+ "source": "iana",
+ "extensions": ["xenc"]
+ },
+ "application/xhtml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xhtml","xht"]
+ },
+ "application/xhtml-voice+xml": {
+ "source": "apache"
+ },
+ "application/xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xml","xsl","xsd"]
+ },
+ "application/xml-dtd": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dtd"]
+ },
+ "application/xml-external-parsed-entity": {
+ "source": "iana"
+ },
+ "application/xml-patch+xml": {
+ "source": "iana"
+ },
+ "application/xmpp+xml": {
+ "source": "iana"
+ },
+ "application/xop+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xop"]
+ },
+ "application/xproc+xml": {
+ "source": "apache",
+ "extensions": ["xpl"]
+ },
+ "application/xslt+xml": {
+ "source": "iana",
+ "extensions": ["xslt"]
+ },
+ "application/xspf+xml": {
+ "source": "apache",
+ "extensions": ["xspf"]
+ },
+ "application/xv+xml": {
+ "source": "iana",
+ "extensions": ["mxml","xhvml","xvml","xvm"]
+ },
+ "application/yang": {
+ "source": "iana",
+ "extensions": ["yang"]
+ },
+ "application/yin+xml": {
+ "source": "iana",
+ "extensions": ["yin"]
+ },
+ "application/zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["zip"]
+ },
+ "application/zlib": {
+ "source": "iana"
+ },
+ "audio/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "audio/32kadpcm": {
+ "source": "iana"
+ },
+ "audio/3gpp": {
+ "source": "iana"
+ },
+ "audio/3gpp2": {
+ "source": "iana"
+ },
+ "audio/ac3": {
+ "source": "iana"
+ },
+ "audio/adpcm": {
+ "source": "apache",
+ "extensions": ["adp"]
+ },
+ "audio/amr": {
+ "source": "iana"
+ },
+ "audio/amr-wb": {
+ "source": "iana"
+ },
+ "audio/amr-wb+": {
+ "source": "iana"
+ },
+ "audio/aptx": {
+ "source": "iana"
+ },
+ "audio/asc": {
+ "source": "iana"
+ },
+ "audio/atrac-advanced-lossless": {
+ "source": "iana"
+ },
+ "audio/atrac-x": {
+ "source": "iana"
+ },
+ "audio/atrac3": {
+ "source": "iana"
+ },
+ "audio/basic": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["au","snd"]
+ },
+ "audio/bv16": {
+ "source": "iana"
+ },
+ "audio/bv32": {
+ "source": "iana"
+ },
+ "audio/clearmode": {
+ "source": "iana"
+ },
+ "audio/cn": {
+ "source": "iana"
+ },
+ "audio/dat12": {
+ "source": "iana"
+ },
+ "audio/dls": {
+ "source": "iana"
+ },
+ "audio/dsr-es201108": {
+ "source": "iana"
+ },
+ "audio/dsr-es202050": {
+ "source": "iana"
+ },
+ "audio/dsr-es202211": {
+ "source": "iana"
+ },
+ "audio/dsr-es202212": {
+ "source": "iana"
+ },
+ "audio/dv": {
+ "source": "iana"
+ },
+ "audio/dvi4": {
+ "source": "iana"
+ },
+ "audio/eac3": {
+ "source": "iana"
+ },
+ "audio/encaprtp": {
+ "source": "iana"
+ },
+ "audio/evrc": {
+ "source": "iana"
+ },
+ "audio/evrc-qcp": {
+ "source": "iana"
+ },
+ "audio/evrc0": {
+ "source": "iana"
+ },
+ "audio/evrc1": {
+ "source": "iana"
+ },
+ "audio/evrcb": {
+ "source": "iana"
+ },
+ "audio/evrcb0": {
+ "source": "iana"
+ },
+ "audio/evrcb1": {
+ "source": "iana"
+ },
+ "audio/evrcnw": {
+ "source": "iana"
+ },
+ "audio/evrcnw0": {
+ "source": "iana"
+ },
+ "audio/evrcnw1": {
+ "source": "iana"
+ },
+ "audio/evrcwb": {
+ "source": "iana"
+ },
+ "audio/evrcwb0": {
+ "source": "iana"
+ },
+ "audio/evrcwb1": {
+ "source": "iana"
+ },
+ "audio/fwdred": {
+ "source": "iana"
+ },
+ "audio/g719": {
+ "source": "iana"
+ },
+ "audio/g722": {
+ "source": "iana"
+ },
+ "audio/g7221": {
+ "source": "iana"
+ },
+ "audio/g723": {
+ "source": "iana"
+ },
+ "audio/g726-16": {
+ "source": "iana"
+ },
+ "audio/g726-24": {
+ "source": "iana"
+ },
+ "audio/g726-32": {
+ "source": "iana"
+ },
+ "audio/g726-40": {
+ "source": "iana"
+ },
+ "audio/g728": {
+ "source": "iana"
+ },
+ "audio/g729": {
+ "source": "iana"
+ },
+ "audio/g7291": {
+ "source": "iana"
+ },
+ "audio/g729d": {
+ "source": "iana"
+ },
+ "audio/g729e": {
+ "source": "iana"
+ },
+ "audio/gsm": {
+ "source": "iana"
+ },
+ "audio/gsm-efr": {
+ "source": "iana"
+ },
+ "audio/gsm-hr-08": {
+ "source": "iana"
+ },
+ "audio/ilbc": {
+ "source": "iana"
+ },
+ "audio/ip-mr_v2.5": {
+ "source": "iana"
+ },
+ "audio/isac": {
+ "source": "apache"
+ },
+ "audio/l16": {
+ "source": "iana"
+ },
+ "audio/l20": {
+ "source": "iana"
+ },
+ "audio/l24": {
+ "source": "iana",
+ "compressible": false
+ },
+ "audio/l8": {
+ "source": "iana"
+ },
+ "audio/lpc": {
+ "source": "iana"
+ },
+ "audio/midi": {
+ "source": "apache",
+ "extensions": ["mid","midi","kar","rmi"]
+ },
+ "audio/mobile-xmf": {
+ "source": "iana"
+ },
+ "audio/mp4": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["mp4a","m4a"]
+ },
+ "audio/mp4a-latm": {
+ "source": "iana"
+ },
+ "audio/mpa": {
+ "source": "iana"
+ },
+ "audio/mpa-robust": {
+ "source": "iana"
+ },
+ "audio/mpeg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["mpga","mp2","mp2a","mp3","m2a","m3a"]
+ },
+ "audio/mpeg4-generic": {
+ "source": "iana"
+ },
+ "audio/musepack": {
+ "source": "apache"
+ },
+ "audio/ogg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["oga","ogg","spx"]
+ },
+ "audio/opus": {
+ "source": "iana"
+ },
+ "audio/parityfec": {
+ "source": "iana"
+ },
+ "audio/pcma": {
+ "source": "iana"
+ },
+ "audio/pcma-wb": {
+ "source": "iana"
+ },
+ "audio/pcmu": {
+ "source": "iana"
+ },
+ "audio/pcmu-wb": {
+ "source": "iana"
+ },
+ "audio/prs.sid": {
+ "source": "iana"
+ },
+ "audio/qcelp": {
+ "source": "iana"
+ },
+ "audio/raptorfec": {
+ "source": "iana"
+ },
+ "audio/red": {
+ "source": "iana"
+ },
+ "audio/rtp-enc-aescm128": {
+ "source": "iana"
+ },
+ "audio/rtp-midi": {
+ "source": "iana"
+ },
+ "audio/rtploopback": {
+ "source": "iana"
+ },
+ "audio/rtx": {
+ "source": "iana"
+ },
+ "audio/s3m": {
+ "source": "apache",
+ "extensions": ["s3m"]
+ },
+ "audio/silk": {
+ "source": "apache",
+ "extensions": ["sil"]
+ },
+ "audio/smv": {
+ "source": "iana"
+ },
+ "audio/smv-qcp": {
+ "source": "iana"
+ },
+ "audio/smv0": {
+ "source": "iana"
+ },
+ "audio/sp-midi": {
+ "source": "iana"
+ },
+ "audio/speex": {
+ "source": "iana"
+ },
+ "audio/t140c": {
+ "source": "iana"
+ },
+ "audio/t38": {
+ "source": "iana"
+ },
+ "audio/telephone-event": {
+ "source": "iana"
+ },
+ "audio/tone": {
+ "source": "iana"
+ },
+ "audio/uemclip": {
+ "source": "iana"
+ },
+ "audio/ulpfec": {
+ "source": "iana"
+ },
+ "audio/vdvi": {
+ "source": "iana"
+ },
+ "audio/vmr-wb": {
+ "source": "iana"
+ },
+ "audio/vnd.3gpp.iufp": {
+ "source": "iana"
+ },
+ "audio/vnd.4sb": {
+ "source": "iana"
+ },
+ "audio/vnd.audiokoz": {
+ "source": "iana"
+ },
+ "audio/vnd.celp": {
+ "source": "iana"
+ },
+ "audio/vnd.cisco.nse": {
+ "source": "iana"
+ },
+ "audio/vnd.cmles.radio-events": {
+ "source": "iana"
+ },
+ "audio/vnd.cns.anp1": {
+ "source": "iana"
+ },
+ "audio/vnd.cns.inf1": {
+ "source": "iana"
+ },
+ "audio/vnd.dece.audio": {
+ "source": "iana",
+ "extensions": ["uva","uvva"]
+ },
+ "audio/vnd.digital-winds": {
+ "source": "iana",
+ "extensions": ["eol"]
+ },
+ "audio/vnd.dlna.adts": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.heaac.1": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.heaac.2": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.mlp": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.mps": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2x": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2z": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pulse.1": {
+ "source": "iana"
+ },
+ "audio/vnd.dra": {
+ "source": "iana",
+ "extensions": ["dra"]
+ },
+ "audio/vnd.dts": {
+ "source": "iana",
+ "extensions": ["dts"]
+ },
+ "audio/vnd.dts.hd": {
+ "source": "iana",
+ "extensions": ["dtshd"]
+ },
+ "audio/vnd.dvb.file": {
+ "source": "iana"
+ },
+ "audio/vnd.everad.plj": {
+ "source": "iana"
+ },
+ "audio/vnd.hns.audio": {
+ "source": "iana"
+ },
+ "audio/vnd.lucent.voice": {
+ "source": "iana",
+ "extensions": ["lvp"]
+ },
+ "audio/vnd.ms-playready.media.pya": {
+ "source": "iana",
+ "extensions": ["pya"]
+ },
+ "audio/vnd.nokia.mobile-xmf": {
+ "source": "iana"
+ },
+ "audio/vnd.nortel.vbk": {
+ "source": "iana"
+ },
+ "audio/vnd.nuera.ecelp4800": {
+ "source": "iana",
+ "extensions": ["ecelp4800"]
+ },
+ "audio/vnd.nuera.ecelp7470": {
+ "source": "iana",
+ "extensions": ["ecelp7470"]
+ },
+ "audio/vnd.nuera.ecelp9600": {
+ "source": "iana",
+ "extensions": ["ecelp9600"]
+ },
+ "audio/vnd.octel.sbc": {
+ "source": "iana"
+ },
+ "audio/vnd.qcelp": {
+ "source": "iana"
+ },
+ "audio/vnd.rhetorex.32kadpcm": {
+ "source": "iana"
+ },
+ "audio/vnd.rip": {
+ "source": "iana",
+ "extensions": ["rip"]
+ },
+ "audio/vnd.rn-realaudio": {
+ "compressible": false
+ },
+ "audio/vnd.sealedmedia.softseal.mpeg": {
+ "source": "iana"
+ },
+ "audio/vnd.vmx.cvsd": {
+ "source": "iana"
+ },
+ "audio/vnd.wave": {
+ "compressible": false
+ },
+ "audio/vorbis": {
+ "source": "iana",
+ "compressible": false
+ },
+ "audio/vorbis-config": {
+ "source": "iana"
+ },
+ "audio/wav": {
+ "compressible": false,
+ "extensions": ["wav"]
+ },
+ "audio/wave": {
+ "compressible": false,
+ "extensions": ["wav"]
+ },
+ "audio/webm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["weba"]
+ },
+ "audio/x-aac": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["aac"]
+ },
+ "audio/x-aiff": {
+ "source": "apache",
+ "extensions": ["aif","aiff","aifc"]
+ },
+ "audio/x-caf": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["caf"]
+ },
+ "audio/x-flac": {
+ "source": "apache",
+ "extensions": ["flac"]
+ },
+ "audio/x-m4a": {
+ "source": "nginx",
+ "extensions": ["m4a"]
+ },
+ "audio/x-matroska": {
+ "source": "apache",
+ "extensions": ["mka"]
+ },
+ "audio/x-mpegurl": {
+ "source": "apache",
+ "extensions": ["m3u"]
+ },
+ "audio/x-ms-wax": {
+ "source": "apache",
+ "extensions": ["wax"]
+ },
+ "audio/x-ms-wma": {
+ "source": "apache",
+ "extensions": ["wma"]
+ },
+ "audio/x-pn-realaudio": {
+ "source": "apache",
+ "extensions": ["ram","ra"]
+ },
+ "audio/x-pn-realaudio-plugin": {
+ "source": "apache",
+ "extensions": ["rmp"]
+ },
+ "audio/x-realaudio": {
+ "source": "nginx",
+ "extensions": ["ra"]
+ },
+ "audio/x-tta": {
+ "source": "apache"
+ },
+ "audio/x-wav": {
+ "source": "apache",
+ "extensions": ["wav"]
+ },
+ "audio/xm": {
+ "source": "apache",
+ "extensions": ["xm"]
+ },
+ "chemical/x-cdx": {
+ "source": "apache",
+ "extensions": ["cdx"]
+ },
+ "chemical/x-cif": {
+ "source": "apache",
+ "extensions": ["cif"]
+ },
+ "chemical/x-cmdf": {
+ "source": "apache",
+ "extensions": ["cmdf"]
+ },
+ "chemical/x-cml": {
+ "source": "apache",
+ "extensions": ["cml"]
+ },
+ "chemical/x-csml": {
+ "source": "apache",
+ "extensions": ["csml"]
+ },
+ "chemical/x-pdb": {
+ "source": "apache"
+ },
+ "chemical/x-xyz": {
+ "source": "apache",
+ "extensions": ["xyz"]
+ },
+ "font/opentype": {
+ "compressible": true,
+ "extensions": ["otf"]
+ },
+ "image/bmp": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["bmp"]
+ },
+ "image/cgm": {
+ "source": "iana",
+ "extensions": ["cgm"]
+ },
+ "image/fits": {
+ "source": "iana"
+ },
+ "image/g3fax": {
+ "source": "iana",
+ "extensions": ["g3"]
+ },
+ "image/gif": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["gif"]
+ },
+ "image/ief": {
+ "source": "iana",
+ "extensions": ["ief"]
+ },
+ "image/jp2": {
+ "source": "iana"
+ },
+ "image/jpeg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jpeg","jpg","jpe"]
+ },
+ "image/jpm": {
+ "source": "iana"
+ },
+ "image/jpx": {
+ "source": "iana"
+ },
+ "image/ktx": {
+ "source": "iana",
+ "extensions": ["ktx"]
+ },
+ "image/naplps": {
+ "source": "iana"
+ },
+ "image/pjpeg": {
+ "compressible": false
+ },
+ "image/png": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["png"]
+ },
+ "image/prs.btif": {
+ "source": "iana",
+ "extensions": ["btif"]
+ },
+ "image/prs.pti": {
+ "source": "iana"
+ },
+ "image/pwg-raster": {
+ "source": "iana"
+ },
+ "image/sgi": {
+ "source": "apache",
+ "extensions": ["sgi"]
+ },
+ "image/svg+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["svg","svgz"]
+ },
+ "image/t38": {
+ "source": "iana"
+ },
+ "image/tiff": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["tiff","tif"]
+ },
+ "image/tiff-fx": {
+ "source": "iana"
+ },
+ "image/vnd.adobe.photoshop": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["psd"]
+ },
+ "image/vnd.airzip.accelerator.azv": {
+ "source": "iana"
+ },
+ "image/vnd.cns.inf2": {
+ "source": "iana"
+ },
+ "image/vnd.dece.graphic": {
+ "source": "iana",
+ "extensions": ["uvi","uvvi","uvg","uvvg"]
+ },
+ "image/vnd.djvu": {
+ "source": "iana",
+ "extensions": ["djvu","djv"]
+ },
+ "image/vnd.dvb.subtitle": {
+ "source": "iana",
+ "extensions": ["sub"]
+ },
+ "image/vnd.dwg": {
+ "source": "iana",
+ "extensions": ["dwg"]
+ },
+ "image/vnd.dxf": {
+ "source": "iana",
+ "extensions": ["dxf"]
+ },
+ "image/vnd.fastbidsheet": {
+ "source": "iana",
+ "extensions": ["fbs"]
+ },
+ "image/vnd.fpx": {
+ "source": "iana",
+ "extensions": ["fpx"]
+ },
+ "image/vnd.fst": {
+ "source": "iana",
+ "extensions": ["fst"]
+ },
+ "image/vnd.fujixerox.edmics-mmr": {
+ "source": "iana",
+ "extensions": ["mmr"]
+ },
+ "image/vnd.fujixerox.edmics-rlc": {
+ "source": "iana",
+ "extensions": ["rlc"]
+ },
+ "image/vnd.globalgraphics.pgb": {
+ "source": "iana"
+ },
+ "image/vnd.microsoft.icon": {
+ "source": "iana"
+ },
+ "image/vnd.mix": {
+ "source": "iana"
+ },
+ "image/vnd.ms-modi": {
+ "source": "iana",
+ "extensions": ["mdi"]
+ },
+ "image/vnd.ms-photo": {
+ "source": "apache",
+ "extensions": ["wdp"]
+ },
+ "image/vnd.net-fpx": {
+ "source": "iana",
+ "extensions": ["npx"]
+ },
+ "image/vnd.radiance": {
+ "source": "iana"
+ },
+ "image/vnd.sealed.png": {
+ "source": "iana"
+ },
+ "image/vnd.sealedmedia.softseal.gif": {
+ "source": "iana"
+ },
+ "image/vnd.sealedmedia.softseal.jpg": {
+ "source": "iana"
+ },
+ "image/vnd.svf": {
+ "source": "iana"
+ },
+ "image/vnd.tencent.tap": {
+ "source": "iana"
+ },
+ "image/vnd.valve.source.texture": {
+ "source": "iana"
+ },
+ "image/vnd.wap.wbmp": {
+ "source": "iana",
+ "extensions": ["wbmp"]
+ },
+ "image/vnd.xiff": {
+ "source": "iana",
+ "extensions": ["xif"]
+ },
+ "image/vnd.zbrush.pcx": {
+ "source": "iana"
+ },
+ "image/webp": {
+ "source": "apache",
+ "extensions": ["webp"]
+ },
+ "image/x-3ds": {
+ "source": "apache",
+ "extensions": ["3ds"]
+ },
+ "image/x-cmu-raster": {
+ "source": "apache",
+ "extensions": ["ras"]
+ },
+ "image/x-cmx": {
+ "source": "apache",
+ "extensions": ["cmx"]
+ },
+ "image/x-freehand": {
+ "source": "apache",
+ "extensions": ["fh","fhc","fh4","fh5","fh7"]
+ },
+ "image/x-icon": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ico"]
+ },
+ "image/x-jng": {
+ "source": "nginx",
+ "extensions": ["jng"]
+ },
+ "image/x-mrsid-image": {
+ "source": "apache",
+ "extensions": ["sid"]
+ },
+ "image/x-ms-bmp": {
+ "source": "nginx",
+ "compressible": true,
+ "extensions": ["bmp"]
+ },
+ "image/x-pcx": {
+ "source": "apache",
+ "extensions": ["pcx"]
+ },
+ "image/x-pict": {
+ "source": "apache",
+ "extensions": ["pic","pct"]
+ },
+ "image/x-portable-anymap": {
+ "source": "apache",
+ "extensions": ["pnm"]
+ },
+ "image/x-portable-bitmap": {
+ "source": "apache",
+ "extensions": ["pbm"]
+ },
+ "image/x-portable-graymap": {
+ "source": "apache",
+ "extensions": ["pgm"]
+ },
+ "image/x-portable-pixmap": {
+ "source": "apache",
+ "extensions": ["ppm"]
+ },
+ "image/x-rgb": {
+ "source": "apache",
+ "extensions": ["rgb"]
+ },
+ "image/x-tga": {
+ "source": "apache",
+ "extensions": ["tga"]
+ },
+ "image/x-xbitmap": {
+ "source": "apache",
+ "extensions": ["xbm"]
+ },
+ "image/x-xcf": {
+ "compressible": false
+ },
+ "image/x-xpixmap": {
+ "source": "apache",
+ "extensions": ["xpm"]
+ },
+ "image/x-xwindowdump": {
+ "source": "apache",
+ "extensions": ["xwd"]
+ },
+ "message/cpim": {
+ "source": "iana"
+ },
+ "message/delivery-status": {
+ "source": "iana"
+ },
+ "message/disposition-notification": {
+ "source": "iana"
+ },
+ "message/external-body": {
+ "source": "iana"
+ },
+ "message/feedback-report": {
+ "source": "iana"
+ },
+ "message/global": {
+ "source": "iana"
+ },
+ "message/global-delivery-status": {
+ "source": "iana"
+ },
+ "message/global-disposition-notification": {
+ "source": "iana"
+ },
+ "message/global-headers": {
+ "source": "iana"
+ },
+ "message/http": {
+ "source": "iana",
+ "compressible": false
+ },
+ "message/imdn+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "message/news": {
+ "source": "iana"
+ },
+ "message/partial": {
+ "source": "iana",
+ "compressible": false
+ },
+ "message/rfc822": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["eml","mime"]
+ },
+ "message/s-http": {
+ "source": "iana"
+ },
+ "message/sip": {
+ "source": "iana"
+ },
+ "message/sipfrag": {
+ "source": "iana"
+ },
+ "message/tracking-status": {
+ "source": "iana"
+ },
+ "message/vnd.si.simp": {
+ "source": "iana"
+ },
+ "message/vnd.wfa.wsc": {
+ "source": "iana"
+ },
+ "model/iges": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["igs","iges"]
+ },
+ "model/mesh": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["msh","mesh","silo"]
+ },
+ "model/vnd.collada+xml": {
+ "source": "iana",
+ "extensions": ["dae"]
+ },
+ "model/vnd.dwf": {
+ "source": "iana",
+ "extensions": ["dwf"]
+ },
+ "model/vnd.flatland.3dml": {
+ "source": "iana"
+ },
+ "model/vnd.gdl": {
+ "source": "iana",
+ "extensions": ["gdl"]
+ },
+ "model/vnd.gs-gdl": {
+ "source": "apache"
+ },
+ "model/vnd.gs.gdl": {
+ "source": "iana"
+ },
+ "model/vnd.gtw": {
+ "source": "iana",
+ "extensions": ["gtw"]
+ },
+ "model/vnd.moml+xml": {
+ "source": "iana"
+ },
+ "model/vnd.mts": {
+ "source": "iana",
+ "extensions": ["mts"]
+ },
+ "model/vnd.opengex": {
+ "source": "iana"
+ },
+ "model/vnd.parasolid.transmit.binary": {
+ "source": "iana"
+ },
+ "model/vnd.parasolid.transmit.text": {
+ "source": "iana"
+ },
+ "model/vnd.valve.source.compiled-map": {
+ "source": "iana"
+ },
+ "model/vnd.vtu": {
+ "source": "iana",
+ "extensions": ["vtu"]
+ },
+ "model/vrml": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["wrl","vrml"]
+ },
+ "model/x3d+binary": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["x3db","x3dbz"]
+ },
+ "model/x3d+fastinfoset": {
+ "source": "iana"
+ },
+ "model/x3d+vrml": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["x3dv","x3dvz"]
+ },
+ "model/x3d+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["x3d","x3dz"]
+ },
+ "model/x3d-vrml": {
+ "source": "iana"
+ },
+ "multipart/alternative": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/appledouble": {
+ "source": "iana"
+ },
+ "multipart/byteranges": {
+ "source": "iana"
+ },
+ "multipart/digest": {
+ "source": "iana"
+ },
+ "multipart/encrypted": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/form-data": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/header-set": {
+ "source": "iana"
+ },
+ "multipart/mixed": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/parallel": {
+ "source": "iana"
+ },
+ "multipart/related": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/report": {
+ "source": "iana"
+ },
+ "multipart/signed": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/voice-message": {
+ "source": "iana"
+ },
+ "multipart/x-mixed-replace": {
+ "source": "iana"
+ },
+ "text/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "text/cache-manifest": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["appcache","manifest"]
+ },
+ "text/calendar": {
+ "source": "iana",
+ "extensions": ["ics","ifb"]
+ },
+ "text/calender": {
+ "compressible": true
+ },
+ "text/cmd": {
+ "compressible": true
+ },
+ "text/coffeescript": {
+ "extensions": ["coffee","litcoffee"]
+ },
+ "text/css": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["css"]
+ },
+ "text/csv": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["csv"]
+ },
+ "text/csv-schema": {
+ "source": "iana"
+ },
+ "text/directory": {
+ "source": "iana"
+ },
+ "text/dns": {
+ "source": "iana"
+ },
+ "text/ecmascript": {
+ "source": "iana"
+ },
+ "text/encaprtp": {
+ "source": "iana"
+ },
+ "text/enriched": {
+ "source": "iana"
+ },
+ "text/fwdred": {
+ "source": "iana"
+ },
+ "text/grammar-ref-list": {
+ "source": "iana"
+ },
+ "text/hjson": {
+ "extensions": ["hjson"]
+ },
+ "text/html": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["html","htm","shtml"]
+ },
+ "text/jade": {
+ "extensions": ["jade"]
+ },
+ "text/javascript": {
+ "source": "iana",
+ "compressible": true
+ },
+ "text/jcr-cnd": {
+ "source": "iana"
+ },
+ "text/jsx": {
+ "compressible": true,
+ "extensions": ["jsx"]
+ },
+ "text/less": {
+ "extensions": ["less"]
+ },
+ "text/markdown": {
+ "source": "iana"
+ },
+ "text/mathml": {
+ "source": "nginx",
+ "extensions": ["mml"]
+ },
+ "text/mizar": {
+ "source": "iana"
+ },
+ "text/n3": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["n3"]
+ },
+ "text/parameters": {
+ "source": "iana"
+ },
+ "text/parityfec": {
+ "source": "iana"
+ },
+ "text/plain": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["txt","text","conf","def","list","log","in","ini"]
+ },
+ "text/provenance-notation": {
+ "source": "iana"
+ },
+ "text/prs.fallenstein.rst": {
+ "source": "iana"
+ },
+ "text/prs.lines.tag": {
+ "source": "iana",
+ "extensions": ["dsc"]
+ },
+ "text/raptorfec": {
+ "source": "iana"
+ },
+ "text/red": {
+ "source": "iana"
+ },
+ "text/rfc822-headers": {
+ "source": "iana"
+ },
+ "text/richtext": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtx"]
+ },
+ "text/rtf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtf"]
+ },
+ "text/rtp-enc-aescm128": {
+ "source": "iana"
+ },
+ "text/rtploopback": {
+ "source": "iana"
+ },
+ "text/rtx": {
+ "source": "iana"
+ },
+ "text/sgml": {
+ "source": "iana",
+ "extensions": ["sgml","sgm"]
+ },
+ "text/stylus": {
+ "extensions": ["stylus","styl"]
+ },
+ "text/t140": {
+ "source": "iana"
+ },
+ "text/tab-separated-values": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["tsv"]
+ },
+ "text/troff": {
+ "source": "iana",
+ "extensions": ["t","tr","roff","man","me","ms"]
+ },
+ "text/turtle": {
+ "source": "iana",
+ "extensions": ["ttl"]
+ },
+ "text/ulpfec": {
+ "source": "iana"
+ },
+ "text/uri-list": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["uri","uris","urls"]
+ },
+ "text/vcard": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["vcard"]
+ },
+ "text/vnd.a": {
+ "source": "iana"
+ },
+ "text/vnd.abc": {
+ "source": "iana"
+ },
+ "text/vnd.curl": {
+ "source": "iana",
+ "extensions": ["curl"]
+ },
+ "text/vnd.curl.dcurl": {
+ "source": "apache",
+ "extensions": ["dcurl"]
+ },
+ "text/vnd.curl.mcurl": {
+ "source": "apache",
+ "extensions": ["mcurl"]
+ },
+ "text/vnd.curl.scurl": {
+ "source": "apache",
+ "extensions": ["scurl"]
+ },
+ "text/vnd.debian.copyright": {
+ "source": "iana"
+ },
+ "text/vnd.dmclientscript": {
+ "source": "iana"
+ },
+ "text/vnd.dvb.subtitle": {
+ "source": "iana",
+ "extensions": ["sub"]
+ },
+ "text/vnd.esmertec.theme-descriptor": {
+ "source": "iana"
+ },
+ "text/vnd.fly": {
+ "source": "iana",
+ "extensions": ["fly"]
+ },
+ "text/vnd.fmi.flexstor": {
+ "source": "iana",
+ "extensions": ["flx"]
+ },
+ "text/vnd.graphviz": {
+ "source": "iana",
+ "extensions": ["gv"]
+ },
+ "text/vnd.in3d.3dml": {
+ "source": "iana",
+ "extensions": ["3dml"]
+ },
+ "text/vnd.in3d.spot": {
+ "source": "iana",
+ "extensions": ["spot"]
+ },
+ "text/vnd.iptc.newsml": {
+ "source": "iana"
+ },
+ "text/vnd.iptc.nitf": {
+ "source": "iana"
+ },
+ "text/vnd.latex-z": {
+ "source": "iana"
+ },
+ "text/vnd.motorola.reflex": {
+ "source": "iana"
+ },
+ "text/vnd.ms-mediapackage": {
+ "source": "iana"
+ },
+ "text/vnd.net2phone.commcenter.command": {
+ "source": "iana"
+ },
+ "text/vnd.radisys.msml-basic-layout": {
+ "source": "iana"
+ },
+ "text/vnd.si.uricatalogue": {
+ "source": "iana"
+ },
+ "text/vnd.sun.j2me.app-descriptor": {
+ "source": "iana",
+ "extensions": ["jad"]
+ },
+ "text/vnd.trolltech.linguist": {
+ "source": "iana"
+ },
+ "text/vnd.wap.si": {
+ "source": "iana"
+ },
+ "text/vnd.wap.sl": {
+ "source": "iana"
+ },
+ "text/vnd.wap.wml": {
+ "source": "iana",
+ "extensions": ["wml"]
+ },
+ "text/vnd.wap.wmlscript": {
+ "source": "iana",
+ "extensions": ["wmls"]
+ },
+ "text/vtt": {
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["vtt"]
+ },
+ "text/x-asm": {
+ "source": "apache",
+ "extensions": ["s","asm"]
+ },
+ "text/x-c": {
+ "source": "apache",
+ "extensions": ["c","cc","cxx","cpp","h","hh","dic"]
+ },
+ "text/x-component": {
+ "source": "nginx",
+ "extensions": ["htc"]
+ },
+ "text/x-fortran": {
+ "source": "apache",
+ "extensions": ["f","for","f77","f90"]
+ },
+ "text/x-gwt-rpc": {
+ "compressible": true
+ },
+ "text/x-handlebars-template": {
+ "extensions": ["hbs"]
+ },
+ "text/x-java-source": {
+ "source": "apache",
+ "extensions": ["java"]
+ },
+ "text/x-jquery-tmpl": {
+ "compressible": true
+ },
+ "text/x-lua": {
+ "extensions": ["lua"]
+ },
+ "text/x-markdown": {
+ "compressible": true,
+ "extensions": ["markdown","md","mkd"]
+ },
+ "text/x-nfo": {
+ "source": "apache",
+ "extensions": ["nfo"]
+ },
+ "text/x-opml": {
+ "source": "apache",
+ "extensions": ["opml"]
+ },
+ "text/x-pascal": {
+ "source": "apache",
+ "extensions": ["p","pas"]
+ },
+ "text/x-processing": {
+ "compressible": true,
+ "extensions": ["pde"]
+ },
+ "text/x-sass": {
+ "extensions": ["sass"]
+ },
+ "text/x-scss": {
+ "extensions": ["scss"]
+ },
+ "text/x-setext": {
+ "source": "apache",
+ "extensions": ["etx"]
+ },
+ "text/x-sfv": {
+ "source": "apache",
+ "extensions": ["sfv"]
+ },
+ "text/x-uuencode": {
+ "source": "apache",
+ "extensions": ["uu"]
+ },
+ "text/x-vcalendar": {
+ "source": "apache",
+ "extensions": ["vcs"]
+ },
+ "text/x-vcard": {
+ "source": "apache",
+ "extensions": ["vcf"]
+ },
+ "text/xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xml"]
+ },
+ "text/xml-external-parsed-entity": {
+ "source": "iana"
+ },
+ "text/yaml": {
+ "extensions": ["yaml","yml"]
+ },
+ "video/1d-interleaved-parityfec": {
+ "source": "apache"
+ },
+ "video/3gpp": {
+ "source": "apache",
+ "extensions": ["3gp","3gpp"]
+ },
+ "video/3gpp-tt": {
+ "source": "apache"
+ },
+ "video/3gpp2": {
+ "source": "apache",
+ "extensions": ["3g2"]
+ },
+ "video/bmpeg": {
+ "source": "apache"
+ },
+ "video/bt656": {
+ "source": "apache"
+ },
+ "video/celb": {
+ "source": "apache"
+ },
+ "video/dv": {
+ "source": "apache"
+ },
+ "video/h261": {
+ "source": "apache",
+ "extensions": ["h261"]
+ },
+ "video/h263": {
+ "source": "apache",
+ "extensions": ["h263"]
+ },
+ "video/h263-1998": {
+ "source": "apache"
+ },
+ "video/h263-2000": {
+ "source": "apache"
+ },
+ "video/h264": {
+ "source": "apache",
+ "extensions": ["h264"]
+ },
+ "video/h264-rcdo": {
+ "source": "apache"
+ },
+ "video/h264-svc": {
+ "source": "apache"
+ },
+ "video/jpeg": {
+ "source": "apache",
+ "extensions": ["jpgv"]
+ },
+ "video/jpeg2000": {
+ "source": "apache"
+ },
+ "video/jpm": {
+ "source": "apache",
+ "extensions": ["jpm","jpgm"]
+ },
+ "video/mj2": {
+ "source": "apache",
+ "extensions": ["mj2","mjp2"]
+ },
+ "video/mp1s": {
+ "source": "apache"
+ },
+ "video/mp2p": {
+ "source": "apache"
+ },
+ "video/mp2t": {
+ "source": "apache",
+ "extensions": ["ts"]
+ },
+ "video/mp4": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["mp4","mp4v","mpg4"]
+ },
+ "video/mp4v-es": {
+ "source": "apache"
+ },
+ "video/mpeg": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["mpeg","mpg","mpe","m1v","m2v"]
+ },
+ "video/mpeg4-generic": {
+ "source": "apache"
+ },
+ "video/mpv": {
+ "source": "apache"
+ },
+ "video/nv": {
+ "source": "apache"
+ },
+ "video/ogg": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["ogv"]
+ },
+ "video/parityfec": {
+ "source": "apache"
+ },
+ "video/pointer": {
+ "source": "apache"
+ },
+ "video/quicktime": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["qt","mov"]
+ },
+ "video/raw": {
+ "source": "apache"
+ },
+ "video/rtp-enc-aescm128": {
+ "source": "apache"
+ },
+ "video/rtx": {
+ "source": "apache"
+ },
+ "video/smpte292m": {
+ "source": "apache"
+ },
+ "video/ulpfec": {
+ "source": "apache"
+ },
+ "video/vc1": {
+ "source": "apache"
+ },
+ "video/vnd.cctv": {
+ "source": "apache"
+ },
+ "video/vnd.dece.hd": {
+ "source": "apache",
+ "extensions": ["uvh","uvvh"]
+ },
+ "video/vnd.dece.mobile": {
+ "source": "apache",
+ "extensions": ["uvm","uvvm"]
+ },
+ "video/vnd.dece.mp4": {
+ "source": "apache"
+ },
+ "video/vnd.dece.pd": {
+ "source": "apache",
+ "extensions": ["uvp","uvvp"]
+ },
+ "video/vnd.dece.sd": {
+ "source": "apache",
+ "extensions": ["uvs","uvvs"]
+ },
+ "video/vnd.dece.video": {
+ "source": "apache",
+ "extensions": ["uvv","uvvv"]
+ },
+ "video/vnd.directv.mpeg": {
+ "source": "apache"
+ },
+ "video/vnd.directv.mpeg-tts": {
+ "source": "apache"
+ },
+ "video/vnd.dlna.mpeg-tts": {
+ "source": "apache"
+ },
+ "video/vnd.dvb.file": {
+ "source": "apache",
+ "extensions": ["dvb"]
+ },
+ "video/vnd.fvt": {
+ "source": "apache",
+ "extensions": ["fvt"]
+ },
+ "video/vnd.hns.video": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.1dparityfec-1010": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.1dparityfec-2005": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.2dparityfec-1010": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.2dparityfec-2005": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.ttsavc": {
+ "source": "apache"
+ },
+ "video/vnd.iptvforum.ttsmpeg2": {
+ "source": "apache"
+ },
+ "video/vnd.motorola.video": {
+ "source": "apache"
+ },
+ "video/vnd.motorola.videop": {
+ "source": "apache"
+ },
+ "video/vnd.mpegurl": {
+ "source": "apache",
+ "extensions": ["mxu","m4u"]
+ },
+ "video/vnd.ms-playready.media.pyv": {
+ "source": "apache",
+ "extensions": ["pyv"]
+ },
+ "video/vnd.nokia.interleaved-multimedia": {
+ "source": "apache"
+ },
+ "video/vnd.nokia.videovoip": {
+ "source": "apache"
+ },
+ "video/vnd.objectvideo": {
+ "source": "apache"
+ },
+ "video/vnd.sealed.mpeg1": {
+ "source": "apache"
+ },
+ "video/vnd.sealed.mpeg4": {
+ "source": "apache"
+ },
+ "video/vnd.sealed.swf": {
+ "source": "apache"
+ },
+ "video/vnd.sealedmedia.softseal.mov": {
+ "source": "apache"
+ },
+ "video/vnd.uvvu.mp4": {
+ "source": "apache",
+ "extensions": ["uvu","uvvu"]
+ },
+ "video/vnd.vivo": {
+ "source": "apache",
+ "extensions": ["viv"]
+ },
+ "video/webm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["webm"]
+ },
+ "video/x-f4v": {
+ "source": "apache",
+ "extensions": ["f4v"]
+ },
+ "video/x-fli": {
+ "source": "apache",
+ "extensions": ["fli"]
+ },
+ "video/x-flv": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["flv"]
+ },
+ "video/x-m4v": {
+ "source": "apache",
+ "extensions": ["m4v"]
+ },
+ "video/x-matroska": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["mkv","mk3d","mks"]
+ },
+ "video/x-mng": {
+ "source": "apache",
+ "extensions": ["mng"]
+ },
+ "video/x-ms-asf": {
+ "source": "apache",
+ "extensions": ["asf","asx"]
+ },
+ "video/x-ms-vob": {
+ "source": "apache",
+ "extensions": ["vob"]
+ },
+ "video/x-ms-wm": {
+ "source": "apache",
+ "extensions": ["wm"]
+ },
+ "video/x-ms-wmv": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["wmv"]
+ },
+ "video/x-ms-wmx": {
+ "source": "apache",
+ "extensions": ["wmx"]
+ },
+ "video/x-ms-wvx": {
+ "source": "apache",
+ "extensions": ["wvx"]
+ },
+ "video/x-msvideo": {
+ "source": "apache",
+ "extensions": ["avi"]
+ },
+ "video/x-sgi-movie": {
+ "source": "apache",
+ "extensions": ["movie"]
+ },
+ "video/x-smv": {
+ "source": "apache",
+ "extensions": ["smv"]
+ },
+ "x-conference/x-cooltalk": {
+ "source": "apache",
+ "extensions": ["ice"]
+ },
+ "x-shader/x-fragment": {
+ "compressible": true
+ },
+ "x-shader/x-vertex": {
+ "compressible": true
+ }
+}
diff --git a/node_modules/request/node_modules/mime-db/index.js b/node_modules/request/node_modules/mime-db/index.js
new file mode 100644
index 000000000..551031f69
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/index.js
@@ -0,0 +1,11 @@
+/*!
+ * mime-db
+ * Copyright(c) 2014 Jonathan Ong
+ * MIT Licensed
+ */
+
+/**
+ * Module exports.
+ */
+
+module.exports = require('./db.json')
diff --git a/node_modules/request/node_modules/mime-db/package.json b/node_modules/request/node_modules/mime-db/package.json
new file mode 100644
index 000000000..7f37773ce
--- /dev/null
+++ b/node_modules/request/node_modules/mime-db/package.json
@@ -0,0 +1,118 @@
+{
+ "_args": [
+ [
+ "mime-db@~1.15.0",
+ "/Users/rebecca/code/npm/node_modules/request/node_modules/mime-types"
+ ]
+ ],
+ "_from": "mime-db@>=1.15.0 <1.16.0",
+ "_id": "mime-db@1.15.0",
+ "_inCache": true,
+ "_location": "/request/mime-db",
+ "_npmUser": {
+ "email": "doug@somethingdoug.com",
+ "name": "dougwilson"
+ },
+ "_npmVersion": "1.4.28",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mime-db",
+ "raw": "mime-db@~1.15.0",
+ "rawSpec": "~1.15.0",
+ "scope": null,
+ "spec": ">=1.15.0 <1.16.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request/mime-types"
+ ],
+ "_resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.15.0.tgz",
+ "_shasum": "d219e6214bbcae23a6fa69c0868c4fadc1405e8a",
+ "_shrinkwrap": null,
+ "_spec": "mime-db@~1.15.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request/node_modules/mime-types",
+ "bugs": {
+ "url": "https://github.com/jshttp/mime-db/issues"
+ },
+ "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"
+ }
+ ],
+ "dependencies": {},
+ "description": "Media Type Database",
+ "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"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "d219e6214bbcae23a6fa69c0868c4fadc1405e8a",
+ "tarball": "http://registry.npmjs.org/mime-db/-/mime-db-1.15.0.tgz"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ },
+ "files": [
+ "HISTORY.md",
+ "LICENSE",
+ "README.md",
+ "db.json",
+ "index.js"
+ ],
+ "gitHead": "96922b79fcaacf8c2a95ce3368739ec71c9471a2",
+ "homepage": "https://github.com/jshttp/mime-db",
+ "keywords": [
+ "charset",
+ "charsets",
+ "database",
+ "db",
+ "mime",
+ "type",
+ "types"
+ ],
+ "license": "MIT",
+ "maintainers": [
+ {
+ "name": "jongleberry",
+ "email": "jonathanrichardong@gmail.com"
+ },
+ {
+ "name": "dougwilson",
+ "email": "doug@somethingdoug.com"
+ }
+ ],
+ "name": "mime-db",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jshttp/mime-db"
+ },
+ "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"
+ },
+ "version": "1.15.0"
+}
diff --git a/node_modules/request/node_modules/mime-types/HISTORY.md b/node_modules/request/node_modules/mime-types/HISTORY.md
new file mode 100644
index 000000000..c5b8f5f13
--- /dev/null
+++ b/node_modules/request/node_modules/mime-types/HISTORY.md
@@ -0,0 +1,147 @@
+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
diff --git a/node_modules/request/node_modules/mime-types/LICENSE b/node_modules/request/node_modules/mime-types/LICENSE
new file mode 100644
index 000000000..06166077b
--- /dev/null
+++ b/node_modules/request/node_modules/mime-types/LICENSE
@@ -0,0 +1,23 @@
+(The MIT License)
+
+Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
+Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/request/node_modules/mime-types/README.md b/node_modules/request/node_modules/mime-types/README.md
new file mode 100644
index 000000000..e26295d04
--- /dev/null
+++ b/node_modules/request/node_modules/mime-types/README.md
@@ -0,0 +1,103 @@
+# mime-types
+
+[![NPM Version][npm-image]][npm-url]
+[![NPM Downloads][downloads-image]][downloads-url]
+[![Node.js Version][node-version-image]][node-version-url]
+[![Build Status][travis-image]][travis-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+
+The ultimate javascript content-type utility.
+
+Similar to [node-mime](https://github.com/broofa/node-mime), except:
+
+- __No fallbacks.__ Instead of naively returning the first available type, `mime-types` simply returns `false`,
+ so do `var type = mime.lookup('unrecognized') || 'application/octet-stream'`.
+- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.
+- Additional mime types are added such as jade and stylus via [mime-db](https://github.com/jshttp/mime-db)
+- No `.define()` functionality
+
+Otherwise, the API is compatible.
+
+## Install
+
+```sh
+$ npm install mime-types
+```
+
+## Adding Types
+
+All mime types are based on [mime-db](https://github.com/jshttp/mime-db),
+so open a PR there if you'd like to add mime types.
+
+## API
+
+```js
+var mime = require('mime-types')
+```
+
+All functions return `false` if input is invalid or not found.
+
+### mime.lookup(path)
+
+Lookup the content-type associated with a file.
+
+```js
+mime.lookup('json') // 'application/json'
+mime.lookup('.md') // 'text/x-markdown'
+mime.lookup('file.html') // 'text/html'
+mime.lookup('folder/file.js') // 'application/javascript'
+mime.lookup('folder/.htaccess') // false
+
+mime.lookup('cats') // false
+```
+
+### mime.contentType(type)
+
+Create a full content-type header given a content-type or extension.
+
+```js
+mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
+mime.contentType('file.json') // 'application/json; charset=utf-8'
+
+// from a full path
+mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'
+```
+
+### mime.extension(type)
+
+Get the default extension for a content-type.
+
+```js
+mime.extension('application/octet-stream') // 'bin'
+```
+
+### mime.charset(type)
+
+Lookup the implied default charset of a content-type.
+
+```js
+mime.charset('text/x-markdown') // 'UTF-8'
+```
+
+### var type = mime.types[extension]
+
+A map of content-types by extension.
+
+### [extensions...] = mime.extensions[type]
+
+A map of extensions by content-type.
+
+## License
+
+[MIT](LICENSE)
+
+[npm-image]: https://img.shields.io/npm/v/mime-types.svg
+[npm-url]: https://npmjs.org/package/mime-types
+[node-version-image]: https://img.shields.io/node/v/mime-types.svg
+[node-version-url]: http://nodejs.org/download/
+[travis-image]: https://img.shields.io/travis/jshttp/mime-types/master.svg
+[travis-url]: https://travis-ci.org/jshttp/mime-types
+[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-types/master.svg
+[coveralls-url]: https://coveralls.io/r/jshttp/mime-types
+[downloads-image]: https://img.shields.io/npm/dm/mime-types.svg
+[downloads-url]: https://npmjs.org/package/mime-types
diff --git a/node_modules/request/node_modules/mime-types/index.js b/node_modules/request/node_modules/mime-types/index.js
new file mode 100644
index 000000000..9edf72b75
--- /dev/null
+++ b/node_modules/request/node_modules/mime-types/index.js
@@ -0,0 +1,188 @@
+/*!
+ * mime-types
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var db = require('mime-db')
+var extname = require('path').extname
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var extractTypeRegExp = /^\s*([^;\s]*)(?:;|\s|$)/
+var textTypeRegExp = /^text\//i
+
+/**
+ * Module exports.
+ * @public
+ */
+
+exports.charset = charset
+exports.charsets = { lookup: charset }
+exports.contentType = contentType
+exports.extension = extension
+exports.extensions = Object.create(null)
+exports.lookup = lookup
+exports.types = Object.create(null)
+
+// Populate the extensions/types maps
+populateMaps(exports.extensions, exports.types)
+
+/**
+ * Get the default charset for a MIME type.
+ *
+ * @param {string} type
+ * @return {boolean|string}
+ */
+
+function charset(type) {
+ if (!type || typeof type !== 'string') {
+ return false
+ }
+
+ // TODO: use media-typer
+ var match = extractTypeRegExp.exec(type)
+ var mime = match && db[match[1].toLowerCase()]
+
+ if (mime && mime.charset) {
+ return mime.charset
+ }
+
+ // default text/* to utf-8
+ if (match && textTypeRegExp.test(match[1])) {
+ return 'UTF-8'
+ }
+
+ return false
+}
+
+/**
+ * Create a full Content-Type header given a MIME type or extension.
+ *
+ * @param {string} str
+ * @return {boolean|string}
+ */
+
+function contentType(str) {
+ // TODO: should this even be in this module?
+ if (!str || typeof str !== 'string') {
+ return false
+ }
+
+ var mime = str.indexOf('/') === -1
+ ? exports.lookup(str)
+ : str
+
+ if (!mime) {
+ return false
+ }
+
+ // TODO: use content-type or other module
+ if (mime.indexOf('charset') === -1) {
+ var charset = exports.charset(mime)
+ if (charset) mime += '; charset=' + charset.toLowerCase()
+ }
+
+ return mime
+}
+
+/**
+ * Get the default extension for a MIME type.
+ *
+ * @param {string} type
+ * @return {boolean|string}
+ */
+
+function extension(type) {
+ if (!type || typeof type !== 'string') {
+ return false
+ }
+
+ // TODO: use media-typer
+ var match = extractTypeRegExp.exec(type)
+
+ // get extensions
+ var exts = match && exports.extensions[match[1].toLowerCase()]
+
+ if (!exts || !exts.length) {
+ return false
+ }
+
+ return exts[0]
+}
+
+/**
+ * Lookup the MIME type for a file path/extension.
+ *
+ * @param {string} path
+ * @return {boolean|string}
+ */
+
+function lookup(path) {
+ if (!path || typeof path !== 'string') {
+ return false
+ }
+
+ // get the extension ("ext" or ".ext" or full path)
+ var extension = extname('x.' + path)
+ .toLowerCase()
+ .substr(1)
+
+ if (!extension) {
+ return false
+ }
+
+ return exports.types[extension] || false
+}
+
+/**
+ * Populate the extensions and types maps.
+ * @private
+ */
+
+function populateMaps(extensions, types) {
+ // source preference (least -> most)
+ var preference = ['nginx', 'apache', undefined, 'iana']
+
+ Object.keys(db).forEach(function forEachMimeType(type) {
+ var mime = db[type]
+ var exts = mime.extensions
+
+ if (!exts || !exts.length) {
+ return
+ }
+
+ // mime -> extensions
+ extensions[type] = exts
+
+ // extension -> mime
+ for (var i = 0; i < exts.length; i++) {
+ var extension = exts[i]
+
+ if (types[extension]) {
+ var from = preference.indexOf(db[types[extension]].source)
+ var to = preference.indexOf(mime.source)
+
+ if (types[extension] !== 'application/octet-stream'
+ && from > to || (from === to && types[extension].substr(0, 12) === 'application/')) {
+ // skip the remapping
+ return
+ }
+ }
+
+ // set the extension -> mime
+ types[extension] = type
+ }
+ })
+}
diff --git a/node_modules/request/node_modules/mime-types/package.json b/node_modules/request/node_modules/mime-types/package.json
new file mode 100644
index 000000000..d595fde15
--- /dev/null
+++ b/node_modules/request/node_modules/mime-types/package.json
@@ -0,0 +1,107 @@
+{
+ "_args": [
+ [
+ "mime-types@~2.1.2",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "mime-types@>=2.1.2 <2.2.0",
+ "_id": "mime-types@2.1.3",
+ "_inCache": true,
+ "_location": "/request/mime-types",
+ "_npmUser": {
+ "email": "doug@somethingdoug.com",
+ "name": "dougwilson"
+ },
+ "_npmVersion": "1.4.28",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mime-types",
+ "raw": "mime-types@~2.1.2",
+ "rawSpec": "~2.1.2",
+ "scope": null,
+ "spec": ">=2.1.2 <2.2.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.3.tgz",
+ "_shasum": "f259849c7eb1f85b8f5f826187278a7f74f0c966",
+ "_shrinkwrap": null,
+ "_spec": "mime-types@~2.1.2",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "bugs": {
+ "url": "https://github.com/jshttp/mime-types/issues"
+ },
+ "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"
+ }
+ ],
+ "dependencies": {
+ "mime-db": "~1.15.0"
+ },
+ "description": "The ultimate javascript content-type utility.",
+ "devDependencies": {
+ "istanbul": "0.3.17",
+ "mocha": "~1.21.5"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "f259849c7eb1f85b8f5f826187278a7f74f0c966",
+ "tarball": "http://registry.npmjs.org/mime-types/-/mime-types-2.1.3.tgz"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ },
+ "files": [
+ "HISTORY.md",
+ "LICENSE",
+ "index.js"
+ ],
+ "gitHead": "565c49ad5683d4a123a170da3444ed32ce426c3a",
+ "homepage": "https://github.com/jshttp/mime-types",
+ "keywords": [
+ "mime",
+ "types"
+ ],
+ "license": "MIT",
+ "maintainers": [
+ {
+ "name": "jongleberry",
+ "email": "jonathanrichardong@gmail.com"
+ },
+ {
+ "name": "fishrock123",
+ "email": "fishrock123@rocketmail.com"
+ },
+ {
+ "name": "dougwilson",
+ "email": "doug@somethingdoug.com"
+ }
+ ],
+ "name": "mime-types",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jshttp/mime-types"
+ },
+ "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"
+ },
+ "version": "2.1.3"
+}
diff --git a/node_modules/request/node_modules/qs/.eslintignore b/node_modules/request/node_modules/qs/.eslintignore
new file mode 100644
index 000000000..1521c8b76
--- /dev/null
+++ b/node_modules/request/node_modules/qs/.eslintignore
@@ -0,0 +1 @@
+dist
diff --git a/node_modules/request/node_modules/qs/.npmignore b/node_modules/request/node_modules/qs/.npmignore
new file mode 100644
index 000000000..2abba8d25
--- /dev/null
+++ b/node_modules/request/node_modules/qs/.npmignore
@@ -0,0 +1,19 @@
+.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
diff --git a/node_modules/request/node_modules/qs/.travis.yml b/node_modules/request/node_modules/qs/.travis.yml
new file mode 100644
index 000000000..f50217888
--- /dev/null
+++ b/node_modules/request/node_modules/qs/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+
+node_js:
+ - 0.10
+ - 0.12
+ - iojs
diff --git a/node_modules/request/node_modules/qs/CHANGELOG.md b/node_modules/request/node_modules/qs/CHANGELOG.md
new file mode 100644
index 000000000..1fadc78ee
--- /dev/null
+++ b/node_modules/request/node_modules/qs/CHANGELOG.md
@@ -0,0 +1,88 @@
+
+## [**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
diff --git a/node_modules/request/node_modules/qs/CONTRIBUTING.md b/node_modules/request/node_modules/qs/CONTRIBUTING.md
new file mode 100644
index 000000000..892836159
--- /dev/null
+++ b/node_modules/request/node_modules/qs/CONTRIBUTING.md
@@ -0,0 +1 @@
+Please view our [hapijs contributing guide](https://github.com/hapijs/hapi/blob/master/CONTRIBUTING.md).
diff --git a/node_modules/request/node_modules/qs/LICENSE b/node_modules/request/node_modules/qs/LICENSE
new file mode 100644
index 000000000..d4569487a
--- /dev/null
+++ b/node_modules/request/node_modules/qs/LICENSE
@@ -0,0 +1,28 @@
+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
diff --git a/node_modules/request/node_modules/qs/README.md b/node_modules/request/node_modules/qs/README.md
new file mode 100644
index 000000000..48a0de97f
--- /dev/null
+++ b/node_modules/request/node_modules/qs/README.md
@@ -0,0 +1,317 @@
+# 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: '' }
+
+```
diff --git a/node_modules/request/node_modules/qs/bower.json b/node_modules/request/node_modules/qs/bower.json
new file mode 100644
index 000000000..ffd0641d8
--- /dev/null
+++ b/node_modules/request/node_modules/qs/bower.json
@@ -0,0 +1,22 @@
+{
+ "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"
+ ]
+}
diff --git a/node_modules/request/node_modules/qs/lib/index.js b/node_modules/request/node_modules/qs/lib/index.js
new file mode 100644
index 000000000..0e094933d
--- /dev/null
+++ b/node_modules/request/node_modules/qs/lib/index.js
@@ -0,0 +1,15 @@
+// Load modules
+
+var Stringify = require('./stringify');
+var Parse = require('./parse');
+
+
+// Declare internals
+
+var internals = {};
+
+
+module.exports = {
+ stringify: Stringify,
+ parse: Parse
+};
diff --git a/node_modules/request/node_modules/qs/lib/parse.js b/node_modules/request/node_modules/qs/lib/parse.js
new file mode 100644
index 000000000..e7c56c5ce
--- /dev/null
+++ b/node_modules/request/node_modules/qs/lib/parse.js
@@ -0,0 +1,186 @@
+// 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);
+};
diff --git a/node_modules/request/node_modules/qs/lib/stringify.js b/node_modules/request/node_modules/qs/lib/stringify.js
new file mode 100644
index 000000000..7414284c5
--- /dev/null
+++ b/node_modules/request/node_modules/qs/lib/stringify.js
@@ -0,0 +1,121 @@
+// 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);
+};
diff --git a/node_modules/request/node_modules/qs/lib/utils.js b/node_modules/request/node_modules/qs/lib/utils.js
new file mode 100644
index 000000000..88f314732
--- /dev/null
+++ b/node_modules/request/node_modules/qs/lib/utils.js
@@ -0,0 +1,190 @@
+// 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));
+};
diff --git a/node_modules/request/node_modules/qs/package.json b/node_modules/request/node_modules/qs/package.json
new file mode 100644
index 000000000..d8534e3ad
--- /dev/null
+++ b/node_modules/request/node_modules/qs/package.json
@@ -0,0 +1,80 @@
+{
+ "_args": [
+ [
+ "qs@~4.0.0",
+ "/Users/rebecca/code/npm/node_modules/request"
+ ]
+ ],
+ "_from": "qs@>=4.0.0 <4.1.0",
+ "_id": "qs@4.0.0",
+ "_inCache": true,
+ "_location": "/request/qs",
+ "_nodeVersion": "0.12.4",
+ "_npmUser": {
+ "email": "quitlahok@gmail.com",
+ "name": "nlf"
+ },
+ "_npmVersion": "2.12.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "qs",
+ "raw": "qs@~4.0.0",
+ "rawSpec": "~4.0.0",
+ "scope": null,
+ "spec": ">=4.0.0 <4.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request"
+ ],
+ "_resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
+ "_shasum": "c31d9b74ec27df75e543a86c78728ed8d4623607",
+ "_shrinkwrap": null,
+ "_spec": "qs@~4.0.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request",
+ "bugs": {
+ "url": "https://github.com/hapijs/qs/issues"
+ },
+ "dependencies": {},
+ "description": "A querystring parser that supports nesting and arrays, with a depth limit",
+ "devDependencies": {
+ "browserify": "^10.2.1",
+ "code": "1.x.x",
+ "lab": "5.x.x"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "c31d9b74ec27df75e543a86c78728ed8d4623607",
+ "tarball": "http://registry.npmjs.org/qs/-/qs-4.0.0.tgz"
+ },
+ "gitHead": "e573dd08eae6cce30d2202704691a102dfa3782a",
+ "homepage": "https://github.com/hapijs/qs",
+ "keywords": [
+ "qs",
+ "querystring"
+ ],
+ "license": "BSD-3-Clause",
+ "main": "lib/index.js",
+ "maintainers": [
+ {
+ "name": "nlf",
+ "email": "quitlahok@gmail.com"
+ },
+ {
+ "name": "hueniverse",
+ "email": "eran@hueniverse.com"
+ }
+ ],
+ "name": "qs",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/hapijs/qs.git"
+ },
+ "scripts": {
+ "dist": "browserify --standalone Qs lib/index.js > dist/qs.js",
+ "test": "lab -a code -t 100 -L",
+ "test-cov-html": "lab -a code -r html -o coverage.html"
+ },
+ "version": "4.0.0"
+}
diff --git a/node_modules/request/node_modules/qs/test/parse.js b/node_modules/request/node_modules/qs/test/parse.js
new file mode 100644
index 000000000..a19d76457
--- /dev/null
+++ b/node_modules/request/node_modules/qs/test/parse.js
@@ -0,0 +1,478 @@
+/* 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();
+ });
+});
diff --git a/node_modules/request/node_modules/qs/test/stringify.js b/node_modules/request/node_modules/qs/test/stringify.js
new file mode 100644
index 000000000..48b7803f7
--- /dev/null
+++ b/node_modules/request/node_modules/qs/test/stringify.js
@@ -0,0 +1,259 @@
+/* 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();
+
+ });
+});
diff --git a/node_modules/request/node_modules/qs/test/utils.js b/node_modules/request/node_modules/qs/test/utils.js
new file mode 100644
index 000000000..a9a6b520d
--- /dev/null
+++ b/node_modules/request/node_modules/qs/test/utils.js
@@ -0,0 +1,28 @@
+// 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();
+ });
+});
diff --git a/node_modules/request/node_modules/readable-stream/.npmignore b/node_modules/request/node_modules/readable-stream/.npmignore
new file mode 100644
index 000000000..38344f87a
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/.npmignore
@@ -0,0 +1,5 @@
+build/
+test/
+examples/
+fs.js
+zlib.js \ No newline at end of file
diff --git a/node_modules/request/node_modules/readable-stream/.travis.yml b/node_modules/request/node_modules/readable-stream/.travis.yml
new file mode 100644
index 000000000..a2870dfb1
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/.travis.yml
@@ -0,0 +1,39 @@
+sudo: false
+language: node_js
+before_install:
+ - npm install -g npm
+notifications:
+ email: false
+matrix:
+ include:
+ - node_js: '0.8'
+ env: TASK=test
+ - node_js: '0.10'
+ env: TASK=test
+ - node_js: '0.11'
+ env: TASK=test
+ - node_js: '0.12'
+ env: TASK=test
+ - node_js: 'iojs'
+ env: TASK=test
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=opera BROWSER_VERSION="11..latest"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=ie BROWSER_VERSION="9..latest"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=chrome BROWSER_VERSION="39..beta"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=firefox BROWSER_VERSION="34..beta"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=ipad BROWSER_VERSION="6.0..latest"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=iphone BROWSER_VERSION="6.0..latest"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=safari BROWSER_VERSION="5..latest"
+ - node_js: 'iojs'
+ env: TASK=browser BROWSER_NAME=android BROWSER_VERSION="4.0..latest"
+script: "npm run $TASK"
+env:
+ global:
+ - secure: rE2Vvo7vnjabYNULNyLFxOyt98BoJexDqsiOnfiD6kLYYsiQGfr/sbZkPMOFm9qfQG7pjqx+zZWZjGSswhTt+626C0t/njXqug7Yps4c3dFblzGfreQHp7wNX5TFsvrxd6dAowVasMp61sJcRnB2w8cUzoe3RAYUDHyiHktwqMc=
+ - secure: g9YINaKAdMatsJ28G9jCGbSaguXCyxSTy+pBO6Ch0Cf57ZLOTka3HqDj8p3nV28LUIHZ3ut5WO43CeYKwt4AUtLpBS3a0dndHdY6D83uY6b2qh5hXlrcbeQTq2cvw2y95F7hm4D1kwrgZ7ViqaKggRcEupAL69YbJnxeUDKWEdI=
diff --git a/node_modules/request/node_modules/readable-stream/.zuul.yml b/node_modules/request/node_modules/readable-stream/.zuul.yml
new file mode 100644
index 000000000..96d9cfbd3
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/.zuul.yml
@@ -0,0 +1 @@
+ui: tape
diff --git a/node_modules/request/node_modules/readable-stream/LICENSE b/node_modules/request/node_modules/readable-stream/LICENSE
new file mode 100644
index 000000000..e3d4e695a
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/LICENSE
@@ -0,0 +1,18 @@
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+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.
diff --git a/node_modules/request/node_modules/readable-stream/README.md b/node_modules/request/node_modules/readable-stream/README.md
new file mode 100644
index 000000000..f9fb52059
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/README.md
@@ -0,0 +1,36 @@
+# readable-stream
+
+***Node-core streams for userland*** [![Build Status](https://travis-ci.org/nodejs/readable-stream.svg?branch=master)](https://travis-ci.org/nodejs/readable-stream)
+
+
+[![NPM](https://nodei.co/npm/readable-stream.png?downloads=true&downloadRank=true)](https://nodei.co/npm/readable-stream/)
+[![NPM](https://nodei.co/npm-dl/readable-stream.png?&months=6&height=3)](https://nodei.co/npm/readable-stream/)
+
+
+[![Sauce Test Status](https://saucelabs.com/browser-matrix/readable-stream.svg)](https://saucelabs.com/u/readable-stream)
+
+```bash
+npm install --save readable-stream
+```
+
+***Node-core streams for userland***
+
+This package is a mirror of the Streams2 and Streams3 implementations in
+Node-core, including [documentation](doc/stream.markdown).
+
+If you want to guarantee a stable streams base, regardless of what version of
+Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).
+
+As of version 2.0.0 **readable-stream** uses semantic versioning.
+
+# Streams WG Team Members
+
+* **Chris Dickinson** ([@chrisdickinson](https://github.com/chrisdickinson)) &lt;christopher.s.dickinson@gmail.com&gt;
+ - Release GPG key: 9554F04D7259F04124DE6B476D5A82AC7E37093B
+* **Calvin Metcalf** ([@calvinmetcalf](https://github.com/calvinmetcalf)) &lt;calvin.metcalf@gmail.com&gt;
+ - Release GPG key: F3EF5F62A87FC27A22E643F714CE4FF5015AA242
+* **Rod Vagg** ([@rvagg](https://github.com/rvagg)) &lt;rod@vagg.org&gt;
+ - Release GPG key: DD8F2338BAE7501E3DD5AC78C273792F7D83545D
+* **Sam Newman** ([@sonewman](https://github.com/sonewman)) &lt;newmansam@outlook.com&gt;
+* **Mathias Buus** ([@mafintosh](https://github.com/mafintosh)) &lt;mathiasbuus@gmail.com&gt;
+* **Domenic Denicola** ([@domenic](https://github.com/domenic)) &lt;d@domenic.me&gt;
diff --git a/node_modules/request/node_modules/readable-stream/doc/stream.markdown b/node_modules/request/node_modules/readable-stream/doc/stream.markdown
new file mode 100644
index 000000000..e34dac429
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/doc/stream.markdown
@@ -0,0 +1,1651 @@
+# Stream
+
+ Stability: 2 - Stable
+
+A stream is an abstract interface implemented by various objects in
+io.js. For example a [request to an HTTP
+server](https://iojs.org/dist/v2.3.0/doc/api/http.html#http_http_incomingmessage) is a stream, as is
+[stdout][]. Streams are readable, writable, or both. All streams are
+instances of [EventEmitter][]
+
+You can load the Stream base classes by doing `require('stream')`.
+There are base classes provided for [Readable][] streams, [Writable][]
+streams, [Duplex][] streams, and [Transform][] streams.
+
+This document is split up into 3 sections. The first explains the
+parts of the API that you need to be aware of to use streams in your
+programs. If you never implement a streaming API yourself, you can
+stop there.
+
+The second section explains the parts of the API that you need to use
+if you implement your own custom streams yourself. The API is
+designed to make this easy for you to do.
+
+The third section goes into more depth about how streams work,
+including some of the internal mechanisms and functions that you
+should probably not modify unless you definitely know what you are
+doing.
+
+
+## API for Stream Consumers
+
+<!--type=misc-->
+
+Streams can be either [Readable][], [Writable][], or both ([Duplex][]).
+
+All streams are EventEmitters, but they also have other custom methods
+and properties depending on whether they are Readable, Writable, or
+Duplex.
+
+If a stream is both Readable and Writable, then it implements all of
+the methods and events below. So, a [Duplex][] or [Transform][] stream is
+fully described by this API, though their implementation may be
+somewhat different.
+
+It is not necessary to implement Stream interfaces in order to consume
+streams in your programs. If you **are** implementing streaming
+interfaces in your own program, please also refer to
+[API for Stream Implementors][] below.
+
+Almost all io.js programs, no matter how simple, use Streams in some
+way. Here is an example of using Streams in an io.js program:
+
+```javascript
+var http = require('http');
+
+var server = http.createServer(function (req, res) {
+ // req is an http.IncomingMessage, which is a Readable Stream
+ // res is an http.ServerResponse, which is a Writable Stream
+
+ var body = '';
+ // we want to get the data as utf8 strings
+ // If you don't set an encoding, then you'll get Buffer objects
+ req.setEncoding('utf8');
+
+ // Readable streams emit 'data' events once a listener is added
+ req.on('data', function (chunk) {
+ body += chunk;
+ });
+
+ // the end event tells you that you have entire body
+ req.on('end', function () {
+ try {
+ var data = JSON.parse(body);
+ } catch (er) {
+ // uh oh! bad json!
+ res.statusCode = 400;
+ return res.end('error: ' + er.message);
+ }
+
+ // write back something interesting to the user:
+ res.write(typeof data);
+ res.end();
+ });
+});
+
+server.listen(1337);
+
+// $ curl localhost:1337 -d '{}'
+// object
+// $ curl localhost:1337 -d '"foo"'
+// string
+// $ curl localhost:1337 -d 'not json'
+// error: Unexpected token o
+```
+
+### Class: stream.Readable
+
+<!--type=class-->
+
+The Readable stream interface is the abstraction for a *source* of
+data that you are reading from. In other words, data comes *out* of a
+Readable stream.
+
+A Readable stream will not start emitting data until you indicate that
+you are ready to receive it.
+
+Readable streams have two "modes": a **flowing mode** and a **paused
+mode**. When in flowing mode, data is read from the underlying system
+and provided to your program as fast as possible. In paused mode, you
+must explicitly call `stream.read()` to get chunks of data out.
+Streams start out in paused mode.
+
+**Note**: If no data event handlers are attached, and there are no
+[`pipe()`][] destinations, and the stream is switched into flowing
+mode, then data will be lost.
+
+You can switch to flowing mode by doing any of the following:
+
+* Adding a [`'data'` event][] handler to listen for data.
+* Calling the [`resume()`][] method to explicitly open the flow.
+* Calling the [`pipe()`][] method to send the data to a [Writable][].
+
+You can switch back to paused mode by doing either of the following:
+
+* If there are no pipe destinations, by calling the [`pause()`][]
+ method.
+* If there are pipe destinations, by removing any [`'data'` event][]
+ handlers, and removing all pipe destinations by calling the
+ [`unpipe()`][] method.
+
+Note that, for backwards compatibility reasons, removing `'data'`
+event handlers will **not** automatically pause the stream. Also, if
+there are piped destinations, then calling `pause()` will not
+guarantee that the stream will *remain* paused once those
+destinations drain and ask for more data.
+
+Examples of readable streams include:
+
+* [http responses, on the client](https://iojs.org/dist/v2.3.0/doc/api/http.html#http_http_incomingmessage)
+* [http requests, on the server](https://iojs.org/dist/v2.3.0/doc/api/http.html#http_http_incomingmessage)
+* [fs read streams](https://iojs.org/dist/v2.3.0/doc/api/fs.html#fs_class_fs_readstream)
+* [zlib streams][]
+* [crypto streams][]
+* [tcp sockets][]
+* [child process stdout and stderr][]
+* [process.stdin][]
+
+#### Event: 'readable'
+
+When a chunk of data can be read from the stream, it will emit a
+`'readable'` event.
+
+In some cases, listening for a `'readable'` event will cause some data
+to be read into the internal buffer from the underlying system, if it
+hadn't already.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.on('readable', function() {
+ // there is some data to read now
+});
+```
+
+Once the internal buffer is drained, a `readable` event will fire
+again when more data is available.
+
+#### Event: 'data'
+
+* `chunk` {Buffer | String} The chunk of data.
+
+Attaching a `data` event listener to a stream that has not been
+explicitly paused will switch the stream into flowing mode. Data will
+then be passed as soon as it is available.
+
+If you just want to get all the data out of the stream as fast as
+possible, this is the best way to do so.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.on('data', function(chunk) {
+ console.log('got %d bytes of data', chunk.length);
+});
+```
+
+#### Event: 'end'
+
+This event fires when there will be no more data to read.
+
+Note that the `end` event **will not fire** unless the data is
+completely consumed. This can be done by switching into flowing mode,
+or by calling `read()` repeatedly until you get to the end.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.on('data', function(chunk) {
+ console.log('got %d bytes of data', chunk.length);
+});
+readable.on('end', function() {
+ console.log('there will be no more data.');
+});
+```
+
+#### Event: 'close'
+
+Emitted when the underlying resource (for example, the backing file
+descriptor) has been closed. Not all streams will emit this.
+
+#### Event: 'error'
+
+* {Error Object}
+
+Emitted if there was an error receiving data.
+
+#### readable.read([size])
+
+* `size` {Number} Optional argument to specify how much data to read.
+* Return {String | Buffer | null}
+
+The `read()` method pulls some data out of the internal buffer and
+returns it. If there is no data available, then it will return
+`null`.
+
+If you pass in a `size` argument, then it will return that many
+bytes. If `size` bytes are not available, then it will return `null`.
+
+If you do not specify a `size` argument, then it will return all the
+data in the internal buffer.
+
+This method should only be called in paused mode. In flowing mode,
+this method is called automatically until the internal buffer is
+drained.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.on('readable', function() {
+ var chunk;
+ while (null !== (chunk = readable.read())) {
+ console.log('got %d bytes of data', chunk.length);
+ }
+});
+```
+
+If this method returns a data chunk, then it will also trigger the
+emission of a [`'data'` event][].
+
+#### readable.setEncoding(encoding)
+
+* `encoding` {String} The encoding to use.
+* Return: `this`
+
+Call this function to cause the stream to return strings of the
+specified encoding instead of Buffer objects. For example, if you do
+`readable.setEncoding('utf8')`, then the output data will be
+interpreted as UTF-8 data, and returned as strings. If you do
+`readable.setEncoding('hex')`, then the data will be encoded in
+hexadecimal string format.
+
+This properly handles multi-byte characters that would otherwise be
+potentially mangled if you simply pulled the Buffers directly and
+called `buf.toString(encoding)` on them. If you want to read the data
+as strings, always use this method.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.setEncoding('utf8');
+readable.on('data', function(chunk) {
+ assert.equal(typeof chunk, 'string');
+ console.log('got %d characters of string data', chunk.length);
+});
+```
+
+#### readable.resume()
+
+* Return: `this`
+
+This method will cause the readable stream to resume emitting `data`
+events.
+
+This method will switch the stream into flowing mode. If you do *not*
+want to consume the data from a stream, but you *do* want to get to
+its `end` event, you can call [`readable.resume()`][] to open the flow of
+data.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.resume();
+readable.on('end', function() {
+ console.log('got to the end, but did not read anything');
+});
+```
+
+#### readable.pause()
+
+* Return: `this`
+
+This method will cause a stream in flowing mode to stop emitting
+`data` events, switching out of flowing mode. Any data that becomes
+available will remain in the internal buffer.
+
+```javascript
+var readable = getReadableStreamSomehow();
+readable.on('data', function(chunk) {
+ console.log('got %d bytes of data', chunk.length);
+ readable.pause();
+ console.log('there will be no more data for 1 second');
+ setTimeout(function() {
+ console.log('now data will start flowing again');
+ readable.resume();
+ }, 1000);
+});
+```
+
+#### readable.isPaused()
+
+* Return: `Boolean`
+
+This method returns whether or not the `readable` has been **explicitly**
+paused by client code (using `readable.pause()` without a corresponding
+`readable.resume()`).
+
+```javascript
+var readable = new stream.Readable
+
+readable.isPaused() // === false
+readable.pause()
+readable.isPaused() // === true
+readable.resume()
+readable.isPaused() // === false
+```
+
+#### readable.pipe(destination[, options])
+
+* `destination` {[Writable][] Stream} The destination for writing data
+* `options` {Object} Pipe options
+ * `end` {Boolean} End the writer when the reader ends. Default = `true`
+
+This method pulls all the data out of a readable stream, and writes it
+to the supplied destination, automatically managing the flow so that
+the destination is not overwhelmed by a fast readable stream.
+
+Multiple destinations can be piped to safely.
+
+```javascript
+var readable = getReadableStreamSomehow();
+var writable = fs.createWriteStream('file.txt');
+// All the data from readable goes into 'file.txt'
+readable.pipe(writable);
+```
+
+This function returns the destination stream, so you can set up pipe
+chains like so:
+
+```javascript
+var r = fs.createReadStream('file.txt');
+var z = zlib.createGzip();
+var w = fs.createWriteStream('file.txt.gz');
+r.pipe(z).pipe(w);
+```
+
+For example, emulating the Unix `cat` command:
+
+```javascript
+process.stdin.pipe(process.stdout);
+```
+
+By default [`end()`][] is called on the destination when the source stream
+emits `end`, so that `destination` is no longer writable. Pass `{ end:
+false }` as `options` to keep the destination stream open.
+
+This keeps `writer` open so that "Goodbye" can be written at the
+end.
+
+```javascript
+reader.pipe(writer, { end: false });
+reader.on('end', function() {
+ writer.end('Goodbye\n');
+});
+```
+
+Note that `process.stderr` and `process.stdout` are never closed until
+the process exits, regardless of the specified options.
+
+#### readable.unpipe([destination])
+
+* `destination` {[Writable][] Stream} Optional specific stream to unpipe
+
+This method will remove the hooks set up for a previous `pipe()` call.
+
+If the destination is not specified, then all pipes are removed.
+
+If the destination is specified, but no pipe is set up for it, then
+this is a no-op.
+
+```javascript
+var readable = getReadableStreamSomehow();
+var writable = fs.createWriteStream('file.txt');
+// All the data from readable goes into 'file.txt',
+// but only for the first second
+readable.pipe(writable);
+setTimeout(function() {
+ console.log('stop writing to file.txt');
+ readable.unpipe(writable);
+ console.log('manually close the file stream');
+ writable.end();
+}, 1000);
+```
+
+#### readable.unshift(chunk)
+
+* `chunk` {Buffer | String} Chunk of data to unshift onto the read queue
+
+This is useful in certain cases where a stream is being consumed by a
+parser, which needs to "un-consume" some data that it has
+optimistically pulled out of the source, so that the stream can be
+passed on to some other party.
+
+If you find that you must often call `stream.unshift(chunk)` in your
+programs, consider implementing a [Transform][] stream instead. (See API
+for Stream Implementors, below.)
+
+```javascript
+// Pull off a header delimited by \n\n
+// use unshift() if we get too much
+// Call the callback with (error, header, stream)
+var StringDecoder = require('string_decoder').StringDecoder;
+function parseHeader(stream, callback) {
+ stream.on('error', callback);
+ stream.on('readable', onReadable);
+ var decoder = new StringDecoder('utf8');
+ var header = '';
+ function onReadable() {
+ var chunk;
+ while (null !== (chunk = stream.read())) {
+ var str = decoder.write(chunk);
+ if (str.match(/\n\n/)) {
+ // found the header boundary
+ var split = str.split(/\n\n/);
+ header += split.shift();
+ var remaining = split.join('\n\n');
+ var buf = new Buffer(remaining, 'utf8');
+ if (buf.length)
+ stream.unshift(buf);
+ stream.removeListener('error', callback);
+ stream.removeListener('readable', onReadable);
+ // now the body of the message can be read from the stream.
+ callback(null, header, stream);
+ } else {
+ // still reading the header.
+ header += str;
+ }
+ }
+ }
+}
+```
+
+#### readable.wrap(stream)
+
+* `stream` {Stream} An "old style" readable stream
+
+Versions of Node.js prior to v0.10 had streams that did not implement the
+entire Streams API as it is today. (See "Compatibility" below for
+more information.)
+
+If you are using an older io.js library that emits `'data'` events and
+has a [`pause()`][] method that is advisory only, then you can use the
+`wrap()` method to create a [Readable][] stream that uses the old stream
+as its data source.
+
+You will very rarely ever need to call this function, but it exists
+as a convenience for interacting with old io.js programs and libraries.
+
+For example:
+
+```javascript
+var OldReader = require('./old-api-module.js').OldReader;
+var oreader = new OldReader;
+var Readable = require('stream').Readable;
+var myReader = new Readable().wrap(oreader);
+
+myReader.on('readable', function() {
+ myReader.read(); // etc.
+});
+```
+
+
+### Class: stream.Writable
+
+<!--type=class-->
+
+The Writable stream interface is an abstraction for a *destination*
+that you are writing data *to*.
+
+Examples of writable streams include:
+
+* [http requests, on the client](https://iojs.org/dist/v2.3.0/doc/api/http.html#http_class_http_clientrequest)
+* [http responses, on the server](https://iojs.org/dist/v2.3.0/doc/api/http.html#http_class_http_serverresponse)
+* [fs write streams](https://iojs.org/dist/v2.3.0/doc/api/fs.html#fs_class_fs_writestream)
+* [zlib streams][]
+* [crypto streams][]
+* [tcp sockets][]
+* [child process stdin](https://iojs.org/dist/v2.3.0/doc/api/child_process.html#child_process_child_stdin)
+* [process.stdout][], [process.stderr][]
+
+#### writable.write(chunk[, encoding][, callback])
+
+* `chunk` {String | Buffer} The data to write
+* `encoding` {String} The encoding, if `chunk` is a String
+* `callback` {Function} Callback for when this chunk of data is flushed
+* Returns: {Boolean} True if the data was handled completely.
+
+This method writes some data to the underlying system, and calls the
+supplied callback once the data has been fully handled.
+
+The return value indicates if you should continue writing right now.
+If the data had to be buffered internally, then it will return
+`false`. Otherwise, it will return `true`.
+
+This return value is strictly advisory. You MAY continue to write,
+even if it returns `false`. However, writes will be buffered in
+memory, so it is best not to do this excessively. Instead, wait for
+the `drain` event before writing more data.
+
+#### Event: 'drain'
+
+If a [`writable.write(chunk)`][] call returns false, then the `drain`
+event will indicate when it is appropriate to begin writing more data
+to the stream.
+
+```javascript
+// Write the data to the supplied writable stream 1MM times.
+// Be attentive to back-pressure.
+function writeOneMillionTimes(writer, data, encoding, callback) {
+ var i = 1000000;
+ write();
+ function write() {
+ var ok = true;
+ do {
+ i -= 1;
+ if (i === 0) {
+ // last time!
+ writer.write(data, encoding, callback);
+ } else {
+ // see if we should continue, or wait
+ // don't pass the callback, because we're not done yet.
+ ok = writer.write(data, encoding);
+ }
+ } while (i > 0 && ok);
+ if (i > 0) {
+ // had to stop early!
+ // write some more once it drains
+ writer.once('drain', write);
+ }
+ }
+}
+```
+
+#### writable.cork()
+
+Forces buffering of all writes.
+
+Buffered data will be flushed either at `.uncork()` or at `.end()` call.
+
+#### writable.uncork()
+
+Flush all data, buffered since `.cork()` call.
+
+#### writable.setDefaultEncoding(encoding)
+
+* `encoding` {String} The new default encoding
+
+Sets the default encoding for a writable stream.
+
+#### writable.end([chunk][, encoding][, callback])
+
+* `chunk` {String | Buffer} Optional data to write
+* `encoding` {String} The encoding, if `chunk` is a String
+* `callback` {Function} Optional callback for when the stream is finished
+
+Call this method when no more data will be written to the stream. If
+supplied, the callback is attached as a listener on the `finish` event.
+
+Calling [`write()`][] after calling [`end()`][] will raise an error.
+
+```javascript
+// write 'hello, ' and then end with 'world!'
+var file = fs.createWriteStream('example.txt');
+file.write('hello, ');
+file.end('world!');
+// writing more now is not allowed!
+```
+
+#### Event: 'finish'
+
+When the [`end()`][] method has been called, and all data has been flushed
+to the underlying system, this event is emitted.
+
+```javascript
+var writer = getWritableStreamSomehow();
+for (var i = 0; i < 100; i ++) {
+ writer.write('hello, #' + i + '!\n');
+}
+writer.end('this is the end\n');
+writer.on('finish', function() {
+ console.error('all writes are now complete.');
+});
+```
+
+#### Event: 'pipe'
+
+* `src` {[Readable][] Stream} source stream that is piping to this writable
+
+This is emitted whenever the `pipe()` method is called on a readable
+stream, adding this writable to its set of destinations.
+
+```javascript
+var writer = getWritableStreamSomehow();
+var reader = getReadableStreamSomehow();
+writer.on('pipe', function(src) {
+ console.error('something is piping into the writer');
+ assert.equal(src, reader);
+});
+reader.pipe(writer);
+```
+
+#### Event: 'unpipe'
+
+* `src` {[Readable][] Stream} The source stream that [unpiped][] this writable
+
+This is emitted whenever the [`unpipe()`][] method is called on a
+readable stream, removing this writable from its set of destinations.
+
+```javascript
+var writer = getWritableStreamSomehow();
+var reader = getReadableStreamSomehow();
+writer.on('unpipe', function(src) {
+ console.error('something has stopped piping into the writer');
+ assert.equal(src, reader);
+});
+reader.pipe(writer);
+reader.unpipe(writer);
+```
+
+#### Event: 'error'
+
+* {Error object}
+
+Emitted if there was an error when writing or piping data.
+
+### Class: stream.Duplex
+
+Duplex streams are streams that implement both the [Readable][] and
+[Writable][] interfaces. See above for usage.
+
+Examples of Duplex streams include:
+
+* [tcp sockets][]
+* [zlib streams][]
+* [crypto streams][]
+
+
+### Class: stream.Transform
+
+Transform streams are [Duplex][] streams where the output is in some way
+computed from the input. They implement both the [Readable][] and
+[Writable][] interfaces. See above for usage.
+
+Examples of Transform streams include:
+
+* [zlib streams][]
+* [crypto streams][]
+
+
+## API for Stream Implementors
+
+<!--type=misc-->
+
+To implement any sort of stream, the pattern is the same:
+
+1. Extend the appropriate parent class in your own subclass. (The
+ [`util.inherits`][] method is particularly helpful for this.)
+2. Call the appropriate parent class constructor in your constructor,
+ to be sure that the internal mechanisms are set up properly.
+2. Implement one or more specific methods, as detailed below.
+
+The class to extend and the method(s) to implement depend on the sort
+of stream class you are writing:
+
+<table>
+ <thead>
+ <tr>
+ <th>
+ <p>Use-case</p>
+ </th>
+ <th>
+ <p>Class</p>
+ </th>
+ <th>
+ <p>Method(s) to implement</p>
+ </th>
+ </tr>
+ </thead>
+ <tr>
+ <td>
+ <p>Reading only</p>
+ </td>
+ <td>
+ <p>[Readable](#stream_class_stream_readable_1)</p>
+ </td>
+ <td>
+ <p><code>[_read][]</code></p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Writing only</p>
+ </td>
+ <td>
+ <p>[Writable](#stream_class_stream_writable_1)</p>
+ </td>
+ <td>
+ <p><code>[_write][]</code>, <code>_writev</code></p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Reading and writing</p>
+ </td>
+ <td>
+ <p>[Duplex](#stream_class_stream_duplex_1)</p>
+ </td>
+ <td>
+ <p><code>[_read][]</code>, <code>[_write][]</code>, <code>_writev</code></p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Operate on written data, then read the result</p>
+ </td>
+ <td>
+ <p>[Transform](#stream_class_stream_transform_1)</p>
+ </td>
+ <td>
+ <p><code>_transform</code>, <code>_flush</code></p>
+ </td>
+ </tr>
+</table>
+
+In your implementation code, it is very important to never call the
+methods described in [API for Stream Consumers][] above. Otherwise, you
+can potentially cause adverse side effects in programs that consume
+your streaming interfaces.
+
+### Class: stream.Readable
+
+<!--type=class-->
+
+`stream.Readable` is an abstract class designed to be extended with an
+underlying implementation of the [`_read(size)`][] method.
+
+Please see above under [API for Stream Consumers][] for how to consume
+streams in your programs. What follows is an explanation of how to
+implement Readable streams in your programs.
+
+#### Example: A Counting Stream
+
+<!--type=example-->
+
+This is a basic example of a Readable stream. It emits the numerals
+from 1 to 1,000,000 in ascending order, and then ends.
+
+```javascript
+var Readable = require('stream').Readable;
+var util = require('util');
+util.inherits(Counter, Readable);
+
+function Counter(opt) {
+ Readable.call(this, opt);
+ this._max = 1000000;
+ this._index = 1;
+}
+
+Counter.prototype._read = function() {
+ var i = this._index++;
+ if (i > this._max)
+ this.push(null);
+ else {
+ var str = '' + i;
+ var buf = new Buffer(str, 'ascii');
+ this.push(buf);
+ }
+};
+```
+
+#### Example: SimpleProtocol v1 (Sub-optimal)
+
+This is similar to the `parseHeader` function described above, but
+implemented as a custom stream. Also, note that this implementation
+does not convert the incoming data to a string.
+
+However, this would be better implemented as a [Transform][] stream. See
+below for a better implementation.
+
+```javascript
+// A parser for a simple data protocol.
+// The "header" is a JSON object, followed by 2 \n characters, and
+// then a message body.
+//
+// NOTE: This can be done more simply as a Transform stream!
+// Using Readable directly for this is sub-optimal. See the
+// alternative example below under the Transform section.
+
+var Readable = require('stream').Readable;
+var util = require('util');
+
+util.inherits(SimpleProtocol, Readable);
+
+function SimpleProtocol(source, options) {
+ if (!(this instanceof SimpleProtocol))
+ return new SimpleProtocol(source, options);
+
+ Readable.call(this, options);
+ this._inBody = false;
+ this._sawFirstCr = false;
+
+ // source is a readable stream, such as a socket or file
+ this._source = source;
+
+ var self = this;
+ source.on('end', function() {
+ self.push(null);
+ });
+
+ // give it a kick whenever the source is readable
+ // read(0) will not consume any bytes
+ source.on('readable', function() {
+ self.read(0);
+ });
+
+ this._rawHeader = [];
+ this.header = null;
+}
+
+SimpleProtocol.prototype._read = function(n) {
+ if (!this._inBody) {
+ var chunk = this._source.read();
+
+ // if the source doesn't have data, we don't have data yet.
+ if (chunk === null)
+ return this.push('');
+
+ // check if the chunk has a \n\n
+ var split = -1;
+ for (var i = 0; i < chunk.length; i++) {
+ if (chunk[i] === 10) { // '\n'
+ if (this._sawFirstCr) {
+ split = i;
+ break;
+ } else {
+ this._sawFirstCr = true;
+ }
+ } else {
+ this._sawFirstCr = false;
+ }
+ }
+
+ if (split === -1) {
+ // still waiting for the \n\n
+ // stash the chunk, and try again.
+ this._rawHeader.push(chunk);
+ this.push('');
+ } else {
+ this._inBody = true;
+ var h = chunk.slice(0, split);
+ this._rawHeader.push(h);
+ var header = Buffer.concat(this._rawHeader).toString();
+ try {
+ this.header = JSON.parse(header);
+ } catch (er) {
+ this.emit('error', new Error('invalid simple protocol data'));
+ return;
+ }
+ // now, because we got some extra data, unshift the rest
+ // back into the read queue so that our consumer will see it.
+ var b = chunk.slice(split);
+ this.unshift(b);
+
+ // and let them know that we are done parsing the header.
+ this.emit('header', this.header);
+ }
+ } else {
+ // from there on, just provide the data to our consumer.
+ // careful not to push(null), since that would indicate EOF.
+ var chunk = this._source.read();
+ if (chunk) this.push(chunk);
+ }
+};
+
+// Usage:
+// var parser = new SimpleProtocol(source);
+// Now parser is a readable stream that will emit 'header'
+// with the parsed header data.
+```
+
+
+#### new stream.Readable([options])
+
+* `options` {Object}
+ * `highWaterMark` {Number} The maximum number of bytes to store in
+ the internal buffer before ceasing to read from the underlying
+ resource. Default=16kb, or 16 for `objectMode` streams
+ * `encoding` {String} If specified, then buffers will be decoded to
+ strings using the specified encoding. Default=null
+ * `objectMode` {Boolean} Whether this stream should behave
+ as a stream of objects. Meaning that stream.read(n) returns
+ a single value instead of a Buffer of size n. Default=false
+
+In classes that extend the Readable class, make sure to call the
+Readable constructor so that the buffering settings can be properly
+initialized.
+
+#### readable.\_read(size)
+
+* `size` {Number} Number of bytes to read asynchronously
+
+Note: **Implement this function, but do NOT call it directly.**
+
+This function should NOT be called directly. It should be implemented
+by child classes, and only called by the internal Readable class
+methods.
+
+All Readable stream implementations must provide a `_read` method to
+fetch data from the underlying resource.
+
+This method is prefixed with an underscore because it is internal to
+the class that defines it, and should not be called directly by user
+programs. However, you **are** expected to override this method in
+your own extension classes.
+
+When data is available, put it into the read queue by calling
+`readable.push(chunk)`. If `push` returns false, then you should stop
+reading. When `_read` is called again, you should start pushing more
+data.
+
+The `size` argument is advisory. Implementations where a "read" is a
+single call that returns data can use this to know how much data to
+fetch. Implementations where that is not relevant, such as TCP or
+TLS, may ignore this argument, and simply provide data whenever it
+becomes available. There is no need, for example to "wait" until
+`size` bytes are available before calling [`stream.push(chunk)`][].
+
+#### readable.push(chunk[, encoding])
+
+* `chunk` {Buffer | null | String} Chunk of data to push into the read queue
+* `encoding` {String} Encoding of String chunks. Must be a valid
+ Buffer encoding, such as `'utf8'` or `'ascii'`
+* return {Boolean} Whether or not more pushes should be performed
+
+Note: **This function should be called by Readable implementors, NOT
+by consumers of Readable streams.**
+
+The `_read()` function will not be called again until at least one
+`push(chunk)` call is made.
+
+The `Readable` class works by putting data into a read queue to be
+pulled out later by calling the `read()` method when the `'readable'`
+event fires.
+
+The `push()` method will explicitly insert some data into the read
+queue. If it is called with `null` then it will signal the end of the
+data (EOF).
+
+This API is designed to be as flexible as possible. For example,
+you may be wrapping a lower-level source which has some sort of
+pause/resume mechanism, and a data callback. In those cases, you
+could wrap the low-level source object by doing something like this:
+
+```javascript
+// source is an object with readStop() and readStart() methods,
+// and an `ondata` member that gets called when it has data, and
+// an `onend` member that gets called when the data is over.
+
+util.inherits(SourceWrapper, Readable);
+
+function SourceWrapper(options) {
+ Readable.call(this, options);
+
+ this._source = getLowlevelSourceObject();
+ var self = this;
+
+ // Every time there's data, we push it into the internal buffer.
+ this._source.ondata = function(chunk) {
+ // if push() returns false, then we need to stop reading from source
+ if (!self.push(chunk))
+ self._source.readStop();
+ };
+
+ // When the source ends, we push the EOF-signaling `null` chunk
+ this._source.onend = function() {
+ self.push(null);
+ };
+}
+
+// _read will be called when the stream wants to pull more data in
+// the advisory size argument is ignored in this case.
+SourceWrapper.prototype._read = function(size) {
+ this._source.readStart();
+};
+```
+
+
+### Class: stream.Writable
+
+<!--type=class-->
+
+`stream.Writable` is an abstract class designed to be extended with an
+underlying implementation of the [`_write(chunk, encoding, callback)`][] method.
+
+Please see above under [API for Stream Consumers][] for how to consume
+writable streams in your programs. What follows is an explanation of
+how to implement Writable streams in your programs.
+
+#### new stream.Writable([options])
+
+* `options` {Object}
+ * `highWaterMark` {Number} Buffer level when [`write()`][] starts
+ returning false. Default=16kb, or 16 for `objectMode` streams
+ * `decodeStrings` {Boolean} Whether or not to decode strings into
+ Buffers before passing them to [`_write()`][]. Default=true
+ * `objectMode` {Boolean} Whether or not the `write(anyObj)` is
+ a valid operation. If set you can write arbitrary data instead
+ of only `Buffer` / `String` data. Default=false
+
+In classes that extend the Writable class, make sure to call the
+constructor so that the buffering settings can be properly
+initialized.
+
+#### writable.\_write(chunk, encoding, callback)
+
+* `chunk` {Buffer | String} The chunk to be written. Will **always**
+ be a buffer unless the `decodeStrings` option was set to `false`.
+* `encoding` {String} If the chunk is a string, then this is the
+ encoding type. If chunk is a buffer, then this is the special
+ value - 'buffer', ignore it in this case.
+* `callback` {Function} Call this function (optionally with an error
+ argument) when you are done processing the supplied chunk.
+
+All Writable stream implementations must provide a [`_write()`][]
+method to send data to the underlying resource.
+
+Note: **This function MUST NOT be called directly.** It should be
+implemented by child classes, and called by the internal Writable
+class methods only.
+
+Call the callback using the standard `callback(error)` pattern to
+signal that the write completed successfully or with an error.
+
+If the `decodeStrings` flag is set in the constructor options, then
+`chunk` may be a string rather than a Buffer, and `encoding` will
+indicate the sort of string that it is. This is to support
+implementations that have an optimized handling for certain string
+data encodings. If you do not explicitly set the `decodeStrings`
+option to `false`, then you can safely ignore the `encoding` argument,
+and assume that `chunk` will always be a Buffer.
+
+This method is prefixed with an underscore because it is internal to
+the class that defines it, and should not be called directly by user
+programs. However, you **are** expected to override this method in
+your own extension classes.
+
+#### writable.\_writev(chunks, callback)
+
+* `chunks` {Array} The chunks to be written. Each chunk has following
+ format: `{ chunk: ..., encoding: ... }`.
+* `callback` {Function} Call this function (optionally with an error
+ argument) when you are done processing the supplied chunks.
+
+Note: **This function MUST NOT be called directly.** It may be
+implemented by child classes, and called by the internal Writable
+class methods only.
+
+This function is completely optional to implement. In most cases it is
+unnecessary. If implemented, it will be called with all the chunks
+that are buffered in the write queue.
+
+
+### Class: stream.Duplex
+
+<!--type=class-->
+
+A "duplex" stream is one that is both Readable and Writable, such as a
+TCP socket connection.
+
+Note that `stream.Duplex` is an abstract class designed to be extended
+with an underlying implementation of the `_read(size)` and
+[`_write(chunk, encoding, callback)`][] methods as you would with a
+Readable or Writable stream class.
+
+Since JavaScript doesn't have multiple prototypal inheritance, this
+class prototypally inherits from Readable, and then parasitically from
+Writable. It is thus up to the user to implement both the lowlevel
+`_read(n)` method as well as the lowlevel
+[`_write(chunk, encoding, callback)`][] method on extension duplex classes.
+
+#### new stream.Duplex(options)
+
+* `options` {Object} Passed to both Writable and Readable
+ constructors. Also has the following fields:
+ * `allowHalfOpen` {Boolean} Default=true. If set to `false`, then
+ the stream will automatically end the readable side when the
+ writable side ends and vice versa.
+ * `readableObjectMode` {Boolean} Default=false. Sets `objectMode`
+ for readable side of the stream. Has no effect if `objectMode`
+ is `true`.
+ * `writableObjectMode` {Boolean} Default=false. Sets `objectMode`
+ for writable side of the stream. Has no effect if `objectMode`
+ is `true`.
+
+In classes that extend the Duplex class, make sure to call the
+constructor so that the buffering settings can be properly
+initialized.
+
+
+### Class: stream.Transform
+
+A "transform" stream is a duplex stream where the output is causally
+connected in some way to the input, such as a [zlib][] stream or a
+[crypto][] stream.
+
+There is no requirement that the output be the same size as the input,
+the same number of chunks, or arrive at the same time. For example, a
+Hash stream will only ever have a single chunk of output which is
+provided when the input is ended. A zlib stream will produce output
+that is either much smaller or much larger than its input.
+
+Rather than implement the [`_read()`][] and [`_write()`][] methods, Transform
+classes must implement the `_transform()` method, and may optionally
+also implement the `_flush()` method. (See below.)
+
+#### new stream.Transform([options])
+
+* `options` {Object} Passed to both Writable and Readable
+ constructors.
+
+In classes that extend the Transform class, make sure to call the
+constructor so that the buffering settings can be properly
+initialized.
+
+#### transform.\_transform(chunk, encoding, callback)
+
+* `chunk` {Buffer | String} The chunk to be transformed. Will **always**
+ be a buffer unless the `decodeStrings` option was set to `false`.
+* `encoding` {String} If the chunk is a string, then this is the
+ encoding type. If chunk is a buffer, then this is the special
+ value - 'buffer', ignore it in this case.
+* `callback` {Function} Call this function (optionally with an error
+ argument and data) when you are done processing the supplied chunk.
+
+Note: **This function MUST NOT be called directly.** It should be
+implemented by child classes, and called by the internal Transform
+class methods only.
+
+All Transform stream implementations must provide a `_transform`
+method to accept input and produce output.
+
+`_transform` should do whatever has to be done in this specific
+Transform class, to handle the bytes being written, and pass them off
+to the readable portion of the interface. Do asynchronous I/O,
+process things, and so on.
+
+Call `transform.push(outputChunk)` 0 or more times to generate output
+from this input chunk, depending on how much data you want to output
+as a result of this chunk.
+
+Call the callback function only when the current chunk is completely
+consumed. Note that there may or may not be output as a result of any
+particular input chunk. If you supply output as the second argument to the
+callback, it will be passed to push method, in other words the following are
+equivalent:
+
+```javascript
+transform.prototype._transform = function (data, encoding, callback) {
+ this.push(data);
+ callback();
+}
+
+transform.prototype._transform = function (data, encoding, callback) {
+ callback(null, data);
+}
+```
+
+This method is prefixed with an underscore because it is internal to
+the class that defines it, and should not be called directly by user
+programs. However, you **are** expected to override this method in
+your own extension classes.
+
+#### transform.\_flush(callback)
+
+* `callback` {Function} Call this function (optionally with an error
+ argument) when you are done flushing any remaining data.
+
+Note: **This function MUST NOT be called directly.** It MAY be implemented
+by child classes, and if so, will be called by the internal Transform
+class methods only.
+
+In some cases, your transform operation may need to emit a bit more
+data at the end of the stream. For example, a `Zlib` compression
+stream will store up some internal state so that it can optimally
+compress the output. At the end, however, it needs to do the best it
+can with what is left, so that the data will be complete.
+
+In those cases, you can implement a `_flush` method, which will be
+called at the very end, after all the written data is consumed, but
+before emitting `end` to signal the end of the readable side. Just
+like with `_transform`, call `transform.push(chunk)` zero or more
+times, as appropriate, and call `callback` when the flush operation is
+complete.
+
+This method is prefixed with an underscore because it is internal to
+the class that defines it, and should not be called directly by user
+programs. However, you **are** expected to override this method in
+your own extension classes.
+
+#### Events: 'finish' and 'end'
+
+The [`finish`][] and [`end`][] events are from the parent Writable
+and Readable classes respectively. The `finish` event is fired after
+`.end()` is called and all chunks have been processed by `_transform`,
+`end` is fired after all data has been output which is after the callback
+in `_flush` has been called.
+
+#### Example: `SimpleProtocol` parser v2
+
+The example above of a simple protocol parser can be implemented
+simply by using the higher level [Transform][] stream class, similar to
+the `parseHeader` and `SimpleProtocol v1` examples above.
+
+In this example, rather than providing the input as an argument, it
+would be piped into the parser, which is a more idiomatic io.js stream
+approach.
+
+```javascript
+var util = require('util');
+var Transform = require('stream').Transform;
+util.inherits(SimpleProtocol, Transform);
+
+function SimpleProtocol(options) {
+ if (!(this instanceof SimpleProtocol))
+ return new SimpleProtocol(options);
+
+ Transform.call(this, options);
+ this._inBody = false;
+ this._sawFirstCr = false;
+ this._rawHeader = [];
+ this.header = null;
+}
+
+SimpleProtocol.prototype._transform = function(chunk, encoding, done) {
+ if (!this._inBody) {
+ // check if the chunk has a \n\n
+ var split = -1;
+ for (var i = 0; i < chunk.length; i++) {
+ if (chunk[i] === 10) { // '\n'
+ if (this._sawFirstCr) {
+ split = i;
+ break;
+ } else {
+ this._sawFirstCr = true;
+ }
+ } else {
+ this._sawFirstCr = false;
+ }
+ }
+
+ if (split === -1) {
+ // still waiting for the \n\n
+ // stash the chunk, and try again.
+ this._rawHeader.push(chunk);
+ } else {
+ this._inBody = true;
+ var h = chunk.slice(0, split);
+ this._rawHeader.push(h);
+ var header = Buffer.concat(this._rawHeader).toString();
+ try {
+ this.header = JSON.parse(header);
+ } catch (er) {
+ this.emit('error', new Error('invalid simple protocol data'));
+ return;
+ }
+ // and let them know that we are done parsing the header.
+ this.emit('header', this.header);
+
+ // now, because we got some extra data, emit this first.
+ this.push(chunk.slice(split));
+ }
+ } else {
+ // from there on, just provide the data to our consumer as-is.
+ this.push(chunk);
+ }
+ done();
+};
+
+// Usage:
+// var parser = new SimpleProtocol();
+// source.pipe(parser)
+// Now parser is a readable stream that will emit 'header'
+// with the parsed header data.
+```
+
+
+### Class: stream.PassThrough
+
+This is a trivial implementation of a [Transform][] stream that simply
+passes the input bytes across to the output. Its purpose is mainly
+for examples and testing, but there are occasionally use cases where
+it can come in handy as a building block for novel sorts of streams.
+
+
+## Simplified Constructor API
+
+<!--type=misc-->
+
+In simple cases there is now the added benefit of being able to construct a stream without inheritance.
+
+This can be done by passing the appropriate methods as constructor options:
+
+Examples:
+
+### Readable
+```javascript
+var readable = new stream.Readable({
+ read: function(n) {
+ // sets this._read under the hood
+ }
+});
+```
+
+### Writable
+```javascript
+var writable = new stream.Writable({
+ write: function(chunk, encoding, next) {
+ // sets this._write under the hood
+ }
+});
+
+// or
+
+var writable = new stream.Writable({
+ writev: function(chunks, next) {
+ // sets this._writev under the hood
+ }
+});
+```
+
+### Duplex
+```javascript
+var duplex = new stream.Duplex({
+ read: function(n) {
+ // sets this._read under the hood
+ },
+ write: function(chunk, encoding, next) {
+ // sets this._write under the hood
+ }
+});
+
+// or
+
+var duplex = new stream.Duplex({
+ read: function(n) {
+ // sets this._read under the hood
+ },
+ writev: function(chunks, next) {
+ // sets this._writev under the hood
+ }
+});
+```
+
+### Transform
+```javascript
+var transform = new stream.Transform({
+ transform: function(chunk, encoding, next) {
+ // sets this._transform under the hood
+ },
+ flush: function(done) {
+ // sets this._flush under the hood
+ }
+});
+```
+
+## Streams: Under the Hood
+
+<!--type=misc-->
+
+### Buffering
+
+<!--type=misc-->
+
+Both Writable and Readable streams will buffer data on an internal
+object called `_writableState.buffer` or `_readableState.buffer`,
+respectively.
+
+The amount of data that will potentially be buffered depends on the
+`highWaterMark` option which is passed into the constructor.
+
+Buffering in Readable streams happens when the implementation calls
+[`stream.push(chunk)`][]. If the consumer of the Stream does not call
+`stream.read()`, then the data will sit in the internal queue until it
+is consumed.
+
+Buffering in Writable streams happens when the user calls
+[`stream.write(chunk)`][] repeatedly, even when `write()` returns `false`.
+
+The purpose of streams, especially with the `pipe()` method, is to
+limit the buffering of data to acceptable levels, so that sources and
+destinations of varying speed will not overwhelm the available memory.
+
+### `stream.read(0)`
+
+There are some cases where you want to trigger a refresh of the
+underlying readable stream mechanisms, without actually consuming any
+data. In that case, you can call `stream.read(0)`, which will always
+return null.
+
+If the internal read buffer is below the `highWaterMark`, and the
+stream is not currently reading, then calling `read(0)` will trigger
+a low-level `_read` call.
+
+There is almost never a need to do this. However, you will see some
+cases in io.js's internals where this is done, particularly in the
+Readable stream class internals.
+
+### `stream.push('')`
+
+Pushing a zero-byte string or Buffer (when not in [Object mode][]) has an
+interesting side effect. Because it *is* a call to
+[`stream.push()`][], it will end the `reading` process. However, it
+does *not* add any data to the readable buffer, so there's nothing for
+a user to consume.
+
+Very rarely, there are cases where you have no data to provide now,
+but the consumer of your stream (or, perhaps, another bit of your own
+code) will know when to check again, by calling `stream.read(0)`. In
+those cases, you *may* call `stream.push('')`.
+
+So far, the only use case for this functionality is in the
+[tls.CryptoStream][] class, which is deprecated in io.js v1.0. If you
+find that you have to use `stream.push('')`, please consider another
+approach, because it almost certainly indicates that something is
+horribly wrong.
+
+### Compatibility with Older Node.js Versions
+
+<!--type=misc-->
+
+In versions of Node.js prior to v0.10, the Readable stream interface was
+simpler, but also less powerful and less useful.
+
+* Rather than waiting for you to call the `read()` method, `'data'`
+ events would start emitting immediately. If you needed to do some
+ I/O to decide how to handle data, then you had to store the chunks
+ in some kind of buffer so that they would not be lost.
+* The [`pause()`][] method was advisory, rather than guaranteed. This
+ meant that you still had to be prepared to receive `'data'` events
+ even when the stream was in a paused state.
+
+In io.js v1.0 and Node.js v0.10, the Readable class described below was added.
+For backwards compatibility with older Node.js programs, Readable streams
+switch into "flowing mode" when a `'data'` event handler is added, or
+when the [`resume()`][] method is called. The effect is that, even if
+you are not using the new `read()` method and `'readable'` event, you
+no longer have to worry about losing `'data'` chunks.
+
+Most programs will continue to function normally. However, this
+introduces an edge case in the following conditions:
+
+* No [`'data'` event][] handler is added.
+* The [`resume()`][] method is never called.
+* The stream is not piped to any writable destination.
+
+For example, consider the following code:
+
+```javascript
+// WARNING! BROKEN!
+net.createServer(function(socket) {
+
+ // we add an 'end' method, but never consume the data
+ socket.on('end', function() {
+ // It will never get here.
+ socket.end('I got your message (but didnt read it)\n');
+ });
+
+}).listen(1337);
+```
+
+In versions of Node.js prior to v0.10, the incoming message data would be
+simply discarded. However, in io.js v1.0 and Node.js v0.10 and beyond,
+the socket will remain paused forever.
+
+The workaround in this situation is to call the `resume()` method to
+start the flow of data:
+
+```javascript
+// Workaround
+net.createServer(function(socket) {
+
+ socket.on('end', function() {
+ socket.end('I got your message (but didnt read it)\n');
+ });
+
+ // start the flow of data, discarding it.
+ socket.resume();
+
+}).listen(1337);
+```
+
+In addition to new Readable streams switching into flowing mode,
+pre-v0.10 style streams can be wrapped in a Readable class using the
+`wrap()` method.
+
+
+### Object Mode
+
+<!--type=misc-->
+
+Normally, Streams operate on Strings and Buffers exclusively.
+
+Streams that are in **object mode** can emit generic JavaScript values
+other than Buffers and Strings.
+
+A Readable stream in object mode will always return a single item from
+a call to `stream.read(size)`, regardless of what the size argument
+is.
+
+A Writable stream in object mode will always ignore the `encoding`
+argument to `stream.write(data, encoding)`.
+
+The special value `null` still retains its special value for object
+mode streams. That is, for object mode readable streams, `null` as a
+return value from `stream.read()` indicates that there is no more
+data, and [`stream.push(null)`][] will signal the end of stream data
+(`EOF`).
+
+No streams in io.js core are object mode streams. This pattern is only
+used by userland streaming libraries.
+
+You should set `objectMode` in your stream child class constructor on
+the options object. Setting `objectMode` mid-stream is not safe.
+
+For Duplex streams `objectMode` can be set exclusively for readable or
+writable side with `readableObjectMode` and `writableObjectMode`
+respectively. These options can be used to implement parsers and
+serializers with Transform streams.
+
+```javascript
+var util = require('util');
+var StringDecoder = require('string_decoder').StringDecoder;
+var Transform = require('stream').Transform;
+util.inherits(JSONParseStream, Transform);
+
+// Gets \n-delimited JSON string data, and emits the parsed objects
+function JSONParseStream() {
+ if (!(this instanceof JSONParseStream))
+ return new JSONParseStream();
+
+ Transform.call(this, { readableObjectMode : true });
+
+ this._buffer = '';
+ this._decoder = new StringDecoder('utf8');
+}
+
+JSONParseStream.prototype._transform = function(chunk, encoding, cb) {
+ this._buffer += this._decoder.write(chunk);
+ // split on newlines
+ var lines = this._buffer.split(/\r?\n/);
+ // keep the last partial line buffered
+ this._buffer = lines.pop();
+ for (var l = 0; l < lines.length; l++) {
+ var line = lines[l];
+ try {
+ var obj = JSON.parse(line);
+ } catch (er) {
+ this.emit('error', er);
+ return;
+ }
+ // push the parsed object out to the readable consumer
+ this.push(obj);
+ }
+ cb();
+};
+
+JSONParseStream.prototype._flush = function(cb) {
+ // Just handle any leftover
+ var rem = this._buffer.trim();
+ if (rem) {
+ try {
+ var obj = JSON.parse(rem);
+ } catch (er) {
+ this.emit('error', er);
+ return;
+ }
+ // push the parsed object out to the readable consumer
+ this.push(obj);
+ }
+ cb();
+};
+```
+
+
+[EventEmitter]: https://iojs.org/dist/v2.3.0/doc/api/events.html#events_class_events_eventemitter
+[Object mode]: #stream_object_mode
+[`stream.push(chunk)`]: #stream_readable_push_chunk_encoding
+[`stream.push(null)`]: #stream_readable_push_chunk_encoding
+[`stream.push()`]: #stream_readable_push_chunk_encoding
+[`unpipe()`]: #stream_readable_unpipe_destination
+[unpiped]: #stream_readable_unpipe_destination
+[tcp sockets]: https://iojs.org/dist/v2.3.0/doc/api/net.html#net_class_net_socket
+[zlib streams]: zlib.html
+[zlib]: zlib.html
+[crypto streams]: crypto.html
+[crypto]: crypto.html
+[tls.CryptoStream]: https://iojs.org/dist/v2.3.0/doc/api/tls.html#tls_class_cryptostream
+[process.stdin]: https://iojs.org/dist/v2.3.0/doc/api/process.html#process_process_stdin
+[stdout]: https://iojs.org/dist/v2.3.0/doc/api/process.html#process_process_stdout
+[process.stdout]: https://iojs.org/dist/v2.3.0/doc/api/process.html#process_process_stdout
+[process.stderr]: https://iojs.org/dist/v2.3.0/doc/api/process.html#process_process_stderr
+[child process stdout and stderr]: https://iojs.org/dist/v2.3.0/doc/api/child_process.html#child_process_child_stdout
+[API for Stream Consumers]: #stream_api_for_stream_consumers
+[API for Stream Implementors]: #stream_api_for_stream_implementors
+[Readable]: #stream_class_stream_readable
+[Writable]: #stream_class_stream_writable
+[Duplex]: #stream_class_stream_duplex
+[Transform]: #stream_class_stream_transform
+[`end`]: #stream_event_end
+[`finish`]: #stream_event_finish
+[`_read(size)`]: #stream_readable_read_size_1
+[`_read()`]: #stream_readable_read_size_1
+[_read]: #stream_readable_read_size_1
+[`writable.write(chunk)`]: #stream_writable_write_chunk_encoding_callback
+[`write(chunk, encoding, callback)`]: #stream_writable_write_chunk_encoding_callback
+[`write()`]: #stream_writable_write_chunk_encoding_callback
+[`stream.write(chunk)`]: #stream_writable_write_chunk_encoding_callback
+[`_write(chunk, encoding, callback)`]: #stream_writable_write_chunk_encoding_callback_1
+[`_write()`]: #stream_writable_write_chunk_encoding_callback_1
+[_write]: #stream_writable_write_chunk_encoding_callback_1
+[`util.inherits`]: https://iojs.org/dist/v2.3.0/doc/api/util.html#util_util_inherits_constructor_superconstructor
+[`end()`]: #stream_writable_end_chunk_encoding_callback
+[`'data'` event]: #stream_event_data
+[`resume()`]: #stream_readable_resume
+[`readable.resume()`]: #stream_readable_resume
+[`pause()`]: #stream_readable_pause
+[`unpipe()`]: #stream_readable_unpipe_destination
+[`pipe()`]: #stream_readable_pipe_destination_options
diff --git a/node_modules/request/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md b/node_modules/request/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md
new file mode 100644
index 000000000..83275f192
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md
@@ -0,0 +1,60 @@
+# streams WG Meeting 2015-01-30
+
+## Links
+
+* **Google Hangouts Video**: http://www.youtube.com/watch?v=I9nDOSGfwZg
+* **GitHub Issue**: https://github.com/iojs/readable-stream/issues/106
+* **Original Minutes Google Doc**: https://docs.google.com/document/d/17aTgLnjMXIrfjgNaTUnHQO7m3xgzHR2VXBTmi03Qii4/
+
+## Agenda
+
+Extracted from https://github.com/iojs/readable-stream/labels/wg-agenda prior to meeting.
+
+* adopt a charter [#105](https://github.com/iojs/readable-stream/issues/105)
+* release and versioning strategy [#101](https://github.com/iojs/readable-stream/issues/101)
+* simpler stream creation [#102](https://github.com/iojs/readable-stream/issues/102)
+* proposal: deprecate implicit flowing of streams [#99](https://github.com/iojs/readable-stream/issues/99)
+
+## Minutes
+
+### adopt a charter
+
+* group: +1's all around
+
+### What versioning scheme should be adopted?
+* group: +1’s 3.0.0
+* domenic+group: pulling in patches from other sources where appropriate
+* mikeal: version independently, suggesting versions for io.js
+* mikeal+domenic: work with TC to notify in advance of changes
+simpler stream creation
+
+### streamline creation of streams
+* sam: streamline creation of streams
+* domenic: nice simple solution posted
+ but, we lose the opportunity to change the model
+ may not be backwards incompatible (double check keys)
+
+ **action item:** domenic will check
+
+### remove implicit flowing of streams on(‘data’)
+* add isFlowing / isPaused
+* mikeal: worrying that we’re documenting polyfill methods – confuses users
+* domenic: more reflective API is probably good, with warning labels for users
+* new section for mad scientists (reflective stream access)
+* calvin: name the “third state”
+* mikeal: maybe borrow the name from whatwg?
+* domenic: we’re missing the “third state”
+* consensus: kind of difficult to name the third state
+* mikeal: figure out differences in states / compat
+* mathias: always flow on data – eliminates third state
+ * explore what it breaks
+
+**action items:**
+* ask isaac for ability to list packages by what public io.js APIs they use (esp. Stream)
+* ask rod/build for infrastructure
+* **chris**: explore the “flow on data” approach
+* add isPaused/isFlowing
+* add new docs section
+* move isPaused to that section
+
+
diff --git a/node_modules/request/node_modules/readable-stream/duplex.js b/node_modules/request/node_modules/readable-stream/duplex.js
new file mode 100644
index 000000000..ca807af87
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/duplex.js
@@ -0,0 +1 @@
+module.exports = require("./lib/_stream_duplex.js")
diff --git a/node_modules/request/node_modules/readable-stream/lib/_stream_duplex.js b/node_modules/request/node_modules/readable-stream/lib/_stream_duplex.js
new file mode 100644
index 000000000..69558af03
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/lib/_stream_duplex.js
@@ -0,0 +1,82 @@
+// a duplex stream is just a stream that is both readable and writable.
+// Since JS doesn't have multiple prototypal inheritance, this class
+// prototypally inherits from Readable, and then parasitically from
+// Writable.
+
+'use strict';
+
+/*<replacement>*/
+var objectKeys = Object.keys || function (obj) {
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ return keys;
+}
+/*</replacement>*/
+
+
+module.exports = Duplex;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+var Readable = require('./_stream_readable');
+var Writable = require('./_stream_writable');
+
+util.inherits(Duplex, Readable);
+
+var keys = objectKeys(Writable.prototype);
+for (var v = 0; v < keys.length; v++) {
+ var method = keys[v];
+ if (!Duplex.prototype[method])
+ Duplex.prototype[method] = Writable.prototype[method];
+}
+
+function Duplex(options) {
+ if (!(this instanceof Duplex))
+ return new Duplex(options);
+
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ if (options && options.readable === false)
+ this.readable = false;
+
+ if (options && options.writable === false)
+ this.writable = false;
+
+ this.allowHalfOpen = true;
+ if (options && options.allowHalfOpen === false)
+ this.allowHalfOpen = false;
+
+ this.once('end', onend);
+}
+
+// the no-half-open enforcer
+function onend() {
+ // if we allow half-open state, or if the writable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._writableState.ended)
+ return;
+
+ // no more data can be written.
+ // But allow more writes to happen in this tick.
+ processNextTick(onEndNT, this);
+}
+
+function onEndNT(self) {
+ self.end();
+}
+
+function forEach (xs, f) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ f(xs[i], i);
+ }
+}
diff --git a/node_modules/request/node_modules/readable-stream/lib/_stream_passthrough.js b/node_modules/request/node_modules/readable-stream/lib/_stream_passthrough.js
new file mode 100644
index 000000000..bddfdd015
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/lib/_stream_passthrough.js
@@ -0,0 +1,27 @@
+// a passthrough stream.
+// basically just the most minimal sort of Transform stream.
+// Every written chunk gets output as-is.
+
+'use strict';
+
+module.exports = PassThrough;
+
+var Transform = require('./_stream_transform');
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+util.inherits(PassThrough, Transform);
+
+function PassThrough(options) {
+ if (!(this instanceof PassThrough))
+ return new PassThrough(options);
+
+ Transform.call(this, options);
+}
+
+PassThrough.prototype._transform = function(chunk, encoding, cb) {
+ cb(null, chunk);
+};
diff --git a/node_modules/request/node_modules/readable-stream/lib/_stream_readable.js b/node_modules/request/node_modules/readable-stream/lib/_stream_readable.js
new file mode 100644
index 000000000..eef3d825d
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/lib/_stream_readable.js
@@ -0,0 +1,959 @@
+'use strict';
+
+module.exports = Readable;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+
+/*<replacement>*/
+var isArray = require('isarray');
+/*</replacement>*/
+
+
+/*<replacement>*/
+var Buffer = require('buffer').Buffer;
+/*</replacement>*/
+
+Readable.ReadableState = ReadableState;
+
+var EE = require('events').EventEmitter;
+
+/*<replacement>*/
+if (!EE.listenerCount) EE.listenerCount = function(emitter, type) {
+ return emitter.listeners(type).length;
+};
+/*</replacement>*/
+
+
+
+/*<replacement>*/
+var Stream;
+(function (){try{
+ Stream = require('st' + 'ream');
+}catch(_){}finally{
+ if (!Stream)
+ Stream = require('events').EventEmitter;
+}}())
+/*</replacement>*/
+
+var Buffer = require('buffer').Buffer;
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+
+
+/*<replacement>*/
+var debug = require('util');
+if (debug && debug.debuglog) {
+ debug = debug.debuglog('stream');
+} else {
+ debug = function () {};
+}
+/*</replacement>*/
+
+var StringDecoder;
+
+util.inherits(Readable, Stream);
+
+function ReadableState(options, stream) {
+ var Duplex = require('./_stream_duplex');
+
+ options = options || {};
+
+ // object stream flag. Used to make read(n) ignore n and to
+ // make all the buffer merging and length checks go away
+ this.objectMode = !!options.objectMode;
+
+ if (stream instanceof Duplex)
+ this.objectMode = this.objectMode || !!options.readableObjectMode;
+
+ // the point at which it stops calling _read() to fill the buffer
+ // Note: 0 is a valid value, means "don't call _read preemptively ever"
+ var hwm = options.highWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+ this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = ~~this.highWaterMark;
+
+ this.buffer = [];
+ this.length = 0;
+ this.pipes = null;
+ this.pipesCount = 0;
+ this.flowing = null;
+ this.ended = false;
+ this.endEmitted = false;
+ this.reading = false;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // whenever we return null, then we set a flag to say
+ // that we're awaiting a 'readable' event emission.
+ this.needReadable = false;
+ this.emittedReadable = false;
+ this.readableListening = false;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // when piping, we only care about 'readable' events that happen
+ // after read()ing all the bytes and not getting any pushback.
+ this.ranOut = false;
+
+ // the number of writers that are awaiting a drain event in .pipe()s
+ this.awaitDrain = 0;
+
+ // if true, a maybeReadMore has been scheduled
+ this.readingMore = false;
+
+ this.decoder = null;
+ this.encoding = null;
+ if (options.encoding) {
+ if (!StringDecoder)
+ StringDecoder = require('string_decoder/').StringDecoder;
+ this.decoder = new StringDecoder(options.encoding);
+ this.encoding = options.encoding;
+ }
+}
+
+function Readable(options) {
+ var Duplex = require('./_stream_duplex');
+
+ if (!(this instanceof Readable))
+ return new Readable(options);
+
+ this._readableState = new ReadableState(options, this);
+
+ // legacy
+ this.readable = true;
+
+ if (options && typeof options.read === 'function')
+ this._read = options.read;
+
+ Stream.call(this);
+}
+
+// Manually shove something into the read() buffer.
+// This returns true if the highWaterMark has not been hit yet,
+// similar to how Writable.write() returns true if you should
+// write() some more.
+Readable.prototype.push = function(chunk, encoding) {
+ var state = this._readableState;
+
+ if (!state.objectMode && typeof chunk === 'string') {
+ encoding = encoding || state.defaultEncoding;
+ if (encoding !== state.encoding) {
+ chunk = new Buffer(chunk, encoding);
+ encoding = '';
+ }
+ }
+
+ return readableAddChunk(this, state, chunk, encoding, false);
+};
+
+// Unshift should *always* be something directly out of read()
+Readable.prototype.unshift = function(chunk) {
+ var state = this._readableState;
+ return readableAddChunk(this, state, chunk, '', true);
+};
+
+Readable.prototype.isPaused = function() {
+ return this._readableState.flowing === false;
+};
+
+function readableAddChunk(stream, state, chunk, encoding, addToFront) {
+ var er = chunkInvalid(state, chunk);
+ if (er) {
+ stream.emit('error', er);
+ } else if (chunk === null) {
+ state.reading = false;
+ onEofChunk(stream, state);
+ } else if (state.objectMode || chunk && chunk.length > 0) {
+ if (state.ended && !addToFront) {
+ var e = new Error('stream.push() after EOF');
+ stream.emit('error', e);
+ } else if (state.endEmitted && addToFront) {
+ var e = new Error('stream.unshift() after end event');
+ stream.emit('error', e);
+ } else {
+ if (state.decoder && !addToFront && !encoding)
+ chunk = state.decoder.write(chunk);
+
+ if (!addToFront)
+ state.reading = false;
+
+ // if we want the data now, just emit it.
+ if (state.flowing && state.length === 0 && !state.sync) {
+ stream.emit('data', chunk);
+ stream.read(0);
+ } else {
+ // update the buffer info.
+ state.length += state.objectMode ? 1 : chunk.length;
+ if (addToFront)
+ state.buffer.unshift(chunk);
+ else
+ state.buffer.push(chunk);
+
+ if (state.needReadable)
+ emitReadable(stream);
+ }
+
+ maybeReadMore(stream, state);
+ }
+ } else if (!addToFront) {
+ state.reading = false;
+ }
+
+ return needMoreData(state);
+}
+
+
+
+// if it's past the high water mark, we can push in some more.
+// Also, if we have no data yet, we can stand some
+// more bytes. This is to work around cases where hwm=0,
+// such as the repl. Also, if the push() triggered a
+// readable event, and the user called read(largeNumber) such that
+// needReadable was set, then we ought to push more, so that another
+// 'readable' event will be triggered.
+function needMoreData(state) {
+ return !state.ended &&
+ (state.needReadable ||
+ state.length < state.highWaterMark ||
+ state.length === 0);
+}
+
+// backwards compatibility.
+Readable.prototype.setEncoding = function(enc) {
+ if (!StringDecoder)
+ StringDecoder = require('string_decoder/').StringDecoder;
+ this._readableState.decoder = new StringDecoder(enc);
+ this._readableState.encoding = enc;
+ return this;
+};
+
+// Don't raise the hwm > 128MB
+var MAX_HWM = 0x800000;
+function roundUpToNextPowerOf2(n) {
+ if (n >= MAX_HWM) {
+ n = MAX_HWM;
+ } else {
+ // Get the next highest power of 2
+ n--;
+ for (var p = 1; p < 32; p <<= 1) n |= n >> p;
+ n++;
+ }
+ return n;
+}
+
+function howMuchToRead(n, state) {
+ if (state.length === 0 && state.ended)
+ return 0;
+
+ if (state.objectMode)
+ return n === 0 ? 0 : 1;
+
+ if (n === null || isNaN(n)) {
+ // only flow one buffer at a time
+ if (state.flowing && state.buffer.length)
+ return state.buffer[0].length;
+ else
+ return state.length;
+ }
+
+ if (n <= 0)
+ return 0;
+
+ // If we're asking for more than the target buffer level,
+ // then raise the water mark. Bump up to the next highest
+ // power of 2, to prevent increasing it excessively in tiny
+ // amounts.
+ if (n > state.highWaterMark)
+ state.highWaterMark = roundUpToNextPowerOf2(n);
+
+ // don't have that much. return null, unless we've ended.
+ if (n > state.length) {
+ if (!state.ended) {
+ state.needReadable = true;
+ return 0;
+ } else {
+ return state.length;
+ }
+ }
+
+ return n;
+}
+
+// you can override either this method, or the async _read(n) below.
+Readable.prototype.read = function(n) {
+ debug('read', n);
+ var state = this._readableState;
+ var nOrig = n;
+
+ if (typeof n !== 'number' || n > 0)
+ state.emittedReadable = false;
+
+ // if we're doing read(0) to trigger a readable event, but we
+ // already have a bunch of data in the buffer, then just trigger
+ // the 'readable' event and move on.
+ if (n === 0 &&
+ state.needReadable &&
+ (state.length >= state.highWaterMark || state.ended)) {
+ debug('read: emitReadable', state.length, state.ended);
+ if (state.length === 0 && state.ended)
+ endReadable(this);
+ else
+ emitReadable(this);
+ return null;
+ }
+
+ n = howMuchToRead(n, state);
+
+ // if we've ended, and we're now clear, then finish it up.
+ if (n === 0 && state.ended) {
+ if (state.length === 0)
+ endReadable(this);
+ return null;
+ }
+
+ // All the actual chunk generation logic needs to be
+ // *below* the call to _read. The reason is that in certain
+ // synthetic stream cases, such as passthrough streams, _read
+ // may be a completely synchronous operation which may change
+ // the state of the read buffer, providing enough data when
+ // before there was *not* enough.
+ //
+ // So, the steps are:
+ // 1. Figure out what the state of things will be after we do
+ // a read from the buffer.
+ //
+ // 2. If that resulting state will trigger a _read, then call _read.
+ // Note that this may be asynchronous, or synchronous. Yes, it is
+ // deeply ugly to write APIs this way, but that still doesn't mean
+ // that the Readable class should behave improperly, as streams are
+ // designed to be sync/async agnostic.
+ // Take note if the _read call is sync or async (ie, if the read call
+ // has returned yet), so that we know whether or not it's safe to emit
+ // 'readable' etc.
+ //
+ // 3. Actually pull the requested chunks out of the buffer and return.
+
+ // if we need a readable event, then we need to do some reading.
+ var doRead = state.needReadable;
+ debug('need readable', doRead);
+
+ // if we currently have less than the highWaterMark, then also read some
+ if (state.length === 0 || state.length - n < state.highWaterMark) {
+ doRead = true;
+ debug('length less than watermark', doRead);
+ }
+
+ // however, if we've ended, then there's no point, and if we're already
+ // reading, then it's unnecessary.
+ if (state.ended || state.reading) {
+ doRead = false;
+ debug('reading or ended', doRead);
+ }
+
+ if (doRead) {
+ debug('do read');
+ state.reading = true;
+ state.sync = true;
+ // if the length is currently zero, then we *need* a readable event.
+ if (state.length === 0)
+ state.needReadable = true;
+ // call internal read method
+ this._read(state.highWaterMark);
+ state.sync = false;
+ }
+
+ // If _read pushed data synchronously, then `reading` will be false,
+ // and we need to re-evaluate how much data we can return to the user.
+ if (doRead && !state.reading)
+ n = howMuchToRead(nOrig, state);
+
+ var ret;
+ if (n > 0)
+ ret = fromList(n, state);
+ else
+ ret = null;
+
+ if (ret === null) {
+ state.needReadable = true;
+ n = 0;
+ }
+
+ state.length -= n;
+
+ // If we have nothing in the buffer, then we want to know
+ // as soon as we *do* get something into the buffer.
+ if (state.length === 0 && !state.ended)
+ state.needReadable = true;
+
+ // If we tried to read() past the EOF, then emit end on the next tick.
+ if (nOrig !== n && state.ended && state.length === 0)
+ endReadable(this);
+
+ if (ret !== null)
+ this.emit('data', ret);
+
+ return ret;
+};
+
+function chunkInvalid(state, chunk) {
+ var er = null;
+ if (!(Buffer.isBuffer(chunk)) &&
+ typeof chunk !== 'string' &&
+ chunk !== null &&
+ chunk !== undefined &&
+ !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ return er;
+}
+
+
+function onEofChunk(stream, state) {
+ if (state.ended) return;
+ if (state.decoder) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length) {
+ state.buffer.push(chunk);
+ state.length += state.objectMode ? 1 : chunk.length;
+ }
+ }
+ state.ended = true;
+
+ // emit 'readable' now to make sure it gets picked up.
+ emitReadable(stream);
+}
+
+// Don't emit readable right away in sync mode, because this can trigger
+// another read() call => stack overflow. This way, it might trigger
+// a nextTick recursion warning, but that's not so bad.
+function emitReadable(stream) {
+ var state = stream._readableState;
+ state.needReadable = false;
+ if (!state.emittedReadable) {
+ debug('emitReadable', state.flowing);
+ state.emittedReadable = true;
+ if (state.sync)
+ processNextTick(emitReadable_, stream);
+ else
+ emitReadable_(stream);
+ }
+}
+
+function emitReadable_(stream) {
+ debug('emit readable');
+ stream.emit('readable');
+ flow(stream);
+}
+
+
+// at this point, the user has presumably seen the 'readable' event,
+// and called read() to consume some data. that may have triggered
+// in turn another _read(n) call, in which case reading = true if
+// it's in progress.
+// However, if we're not ended, or reading, and the length < hwm,
+// then go ahead and try to read some more preemptively.
+function maybeReadMore(stream, state) {
+ if (!state.readingMore) {
+ state.readingMore = true;
+ processNextTick(maybeReadMore_, stream, state);
+ }
+}
+
+function maybeReadMore_(stream, state) {
+ var len = state.length;
+ while (!state.reading && !state.flowing && !state.ended &&
+ state.length < state.highWaterMark) {
+ debug('maybeReadMore read 0');
+ stream.read(0);
+ if (len === state.length)
+ // didn't get any data, stop spinning.
+ break;
+ else
+ len = state.length;
+ }
+ state.readingMore = false;
+}
+
+// abstract method. to be overridden in specific implementation classes.
+// call cb(er, data) where data is <= n in length.
+// for virtual (non-string, non-buffer) streams, "length" is somewhat
+// arbitrary, and perhaps not very meaningful.
+Readable.prototype._read = function(n) {
+ this.emit('error', new Error('not implemented'));
+};
+
+Readable.prototype.pipe = function(dest, pipeOpts) {
+ var src = this;
+ var state = this._readableState;
+
+ switch (state.pipesCount) {
+ case 0:
+ state.pipes = dest;
+ break;
+ case 1:
+ state.pipes = [state.pipes, dest];
+ break;
+ default:
+ state.pipes.push(dest);
+ break;
+ }
+ state.pipesCount += 1;
+ debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
+
+ var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
+ dest !== process.stdout &&
+ dest !== process.stderr;
+
+ var endFn = doEnd ? onend : cleanup;
+ if (state.endEmitted)
+ processNextTick(endFn);
+ else
+ src.once('end', endFn);
+
+ dest.on('unpipe', onunpipe);
+ function onunpipe(readable) {
+ debug('onunpipe');
+ if (readable === src) {
+ cleanup();
+ }
+ }
+
+ function onend() {
+ debug('onend');
+ dest.end();
+ }
+
+ // when the dest drains, it reduces the awaitDrain counter
+ // on the source. This would be more elegant with a .once()
+ // handler in flow(), but adding and removing repeatedly is
+ // too slow.
+ var ondrain = pipeOnDrain(src);
+ dest.on('drain', ondrain);
+
+ function cleanup() {
+ debug('cleanup');
+ // cleanup event handlers once the pipe is broken
+ dest.removeListener('close', onclose);
+ dest.removeListener('finish', onfinish);
+ dest.removeListener('drain', ondrain);
+ dest.removeListener('error', onerror);
+ dest.removeListener('unpipe', onunpipe);
+ src.removeListener('end', onend);
+ src.removeListener('end', cleanup);
+ src.removeListener('data', ondata);
+
+ // if the reader is waiting for a drain event from this
+ // specific writer, then it would cause it to never start
+ // flowing again.
+ // So, if this is awaiting a drain, then we just call it now.
+ // If we don't know, then assume that we are waiting for one.
+ if (state.awaitDrain &&
+ (!dest._writableState || dest._writableState.needDrain))
+ ondrain();
+ }
+
+ src.on('data', ondata);
+ function ondata(chunk) {
+ debug('ondata');
+ var ret = dest.write(chunk);
+ if (false === ret) {
+ debug('false write response, pause',
+ src._readableState.awaitDrain);
+ src._readableState.awaitDrain++;
+ src.pause();
+ }
+ }
+
+ // if the dest has an error, then stop piping into it.
+ // however, don't suppress the throwing behavior for this.
+ function onerror(er) {
+ debug('onerror', er);
+ unpipe();
+ dest.removeListener('error', onerror);
+ if (EE.listenerCount(dest, 'error') === 0)
+ dest.emit('error', er);
+ }
+ // This is a brutally ugly hack to make sure that our error handler
+ // is attached before any userland ones. NEVER DO THIS.
+ if (!dest._events || !dest._events.error)
+ dest.on('error', onerror);
+ else if (isArray(dest._events.error))
+ dest._events.error.unshift(onerror);
+ else
+ dest._events.error = [onerror, dest._events.error];
+
+
+
+ // Both close and finish should trigger unpipe, but only once.
+ function onclose() {
+ dest.removeListener('finish', onfinish);
+ unpipe();
+ }
+ dest.once('close', onclose);
+ function onfinish() {
+ debug('onfinish');
+ dest.removeListener('close', onclose);
+ unpipe();
+ }
+ dest.once('finish', onfinish);
+
+ function unpipe() {
+ debug('unpipe');
+ src.unpipe(dest);
+ }
+
+ // tell the dest that it's being piped to
+ dest.emit('pipe', src);
+
+ // start the flow if it hasn't been started already.
+ if (!state.flowing) {
+ debug('pipe resume');
+ src.resume();
+ }
+
+ return dest;
+};
+
+function pipeOnDrain(src) {
+ return function() {
+ var state = src._readableState;
+ debug('pipeOnDrain', state.awaitDrain);
+ if (state.awaitDrain)
+ state.awaitDrain--;
+ if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) {
+ state.flowing = true;
+ flow(src);
+ }
+ };
+}
+
+
+Readable.prototype.unpipe = function(dest) {
+ var state = this._readableState;
+
+ // if we're not piping anywhere, then do nothing.
+ if (state.pipesCount === 0)
+ return this;
+
+ // just one destination. most common case.
+ if (state.pipesCount === 1) {
+ // passed in one, but it's not the right one.
+ if (dest && dest !== state.pipes)
+ return this;
+
+ if (!dest)
+ dest = state.pipes;
+
+ // got a match.
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+ if (dest)
+ dest.emit('unpipe', this);
+ return this;
+ }
+
+ // slow case. multiple pipe destinations.
+
+ if (!dest) {
+ // remove all.
+ var dests = state.pipes;
+ var len = state.pipesCount;
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+
+ for (var i = 0; i < len; i++)
+ dests[i].emit('unpipe', this);
+ return this;
+ }
+
+ // try to find the right one.
+ var i = indexOf(state.pipes, dest);
+ if (i === -1)
+ return this;
+
+ state.pipes.splice(i, 1);
+ state.pipesCount -= 1;
+ if (state.pipesCount === 1)
+ state.pipes = state.pipes[0];
+
+ dest.emit('unpipe', this);
+
+ return this;
+};
+
+// set up data events if they are asked for
+// Ensure readable listeners eventually get something
+Readable.prototype.on = function(ev, fn) {
+ var res = Stream.prototype.on.call(this, ev, fn);
+
+ // If listening to data, and it has not explicitly been paused,
+ // then call resume to start the flow of data on the next tick.
+ if (ev === 'data' && false !== this._readableState.flowing) {
+ this.resume();
+ }
+
+ if (ev === 'readable' && this.readable) {
+ var state = this._readableState;
+ if (!state.readableListening) {
+ state.readableListening = true;
+ state.emittedReadable = false;
+ state.needReadable = true;
+ if (!state.reading) {
+ processNextTick(nReadingNextTick, this);
+ } else if (state.length) {
+ emitReadable(this, state);
+ }
+ }
+ }
+
+ return res;
+};
+Readable.prototype.addListener = Readable.prototype.on;
+
+function nReadingNextTick(self) {
+ debug('readable nexttick read 0');
+ self.read(0);
+}
+
+// pause() and resume() are remnants of the legacy readable stream API
+// If the user uses them, then switch into old mode.
+Readable.prototype.resume = function() {
+ var state = this._readableState;
+ if (!state.flowing) {
+ debug('resume');
+ state.flowing = true;
+ resume(this, state);
+ }
+ return this;
+};
+
+function resume(stream, state) {
+ if (!state.resumeScheduled) {
+ state.resumeScheduled = true;
+ processNextTick(resume_, stream, state);
+ }
+}
+
+function resume_(stream, state) {
+ if (!state.reading) {
+ debug('resume read 0');
+ stream.read(0);
+ }
+
+ state.resumeScheduled = false;
+ stream.emit('resume');
+ flow(stream);
+ if (state.flowing && !state.reading)
+ stream.read(0);
+}
+
+Readable.prototype.pause = function() {
+ debug('call pause flowing=%j', this._readableState.flowing);
+ if (false !== this._readableState.flowing) {
+ debug('pause');
+ this._readableState.flowing = false;
+ this.emit('pause');
+ }
+ return this;
+};
+
+function flow(stream) {
+ var state = stream._readableState;
+ debug('flow', state.flowing);
+ if (state.flowing) {
+ do {
+ var chunk = stream.read();
+ } while (null !== chunk && state.flowing);
+ }
+}
+
+// wrap an old-style stream as the async data source.
+// This is *not* part of the readable stream interface.
+// It is an ugly unfortunate mess of history.
+Readable.prototype.wrap = function(stream) {
+ var state = this._readableState;
+ var paused = false;
+
+ var self = this;
+ stream.on('end', function() {
+ debug('wrapped end');
+ if (state.decoder && !state.ended) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length)
+ self.push(chunk);
+ }
+
+ self.push(null);
+ });
+
+ stream.on('data', function(chunk) {
+ debug('wrapped data');
+ if (state.decoder)
+ chunk = state.decoder.write(chunk);
+
+ // don't skip over falsy values in objectMode
+ if (state.objectMode && (chunk === null || chunk === undefined))
+ return;
+ else if (!state.objectMode && (!chunk || !chunk.length))
+ return;
+
+ var ret = self.push(chunk);
+ if (!ret) {
+ paused = true;
+ stream.pause();
+ }
+ });
+
+ // proxy all the other methods.
+ // important when wrapping filters and duplexes.
+ for (var i in stream) {
+ if (this[i] === undefined && typeof stream[i] === 'function') {
+ this[i] = function(method) { return function() {
+ return stream[method].apply(stream, arguments);
+ }; }(i);
+ }
+ }
+
+ // proxy certain important events.
+ var events = ['error', 'close', 'destroy', 'pause', 'resume'];
+ forEach(events, function(ev) {
+ stream.on(ev, self.emit.bind(self, ev));
+ });
+
+ // when we try to consume some more bytes, simply unpause the
+ // underlying stream.
+ self._read = function(n) {
+ debug('wrapped _read', n);
+ if (paused) {
+ paused = false;
+ stream.resume();
+ }
+ };
+
+ return self;
+};
+
+
+
+// exposed for testing purposes only.
+Readable._fromList = fromList;
+
+// Pluck off n bytes from an array of buffers.
+// Length is the combined lengths of all the buffers in the list.
+function fromList(n, state) {
+ var list = state.buffer;
+ var length = state.length;
+ var stringMode = !!state.decoder;
+ var objectMode = !!state.objectMode;
+ var ret;
+
+ // nothing in the list, definitely empty.
+ if (list.length === 0)
+ return null;
+
+ if (length === 0)
+ ret = null;
+ else if (objectMode)
+ ret = list.shift();
+ else if (!n || n >= length) {
+ // read it all, truncate the array.
+ if (stringMode)
+ ret = list.join('');
+ else
+ ret = Buffer.concat(list, length);
+ list.length = 0;
+ } else {
+ // read just some of it.
+ if (n < list[0].length) {
+ // just take a part of the first list item.
+ // slice is the same for buffers and strings.
+ var buf = list[0];
+ ret = buf.slice(0, n);
+ list[0] = buf.slice(n);
+ } else if (n === list[0].length) {
+ // first list is a perfect match
+ ret = list.shift();
+ } else {
+ // complex case.
+ // we have enough to cover it, but it spans past the first buffer.
+ if (stringMode)
+ ret = '';
+ else
+ ret = new Buffer(n);
+
+ var c = 0;
+ for (var i = 0, l = list.length; i < l && c < n; i++) {
+ var buf = list[0];
+ var cpy = Math.min(n - c, buf.length);
+
+ if (stringMode)
+ ret += buf.slice(0, cpy);
+ else
+ buf.copy(ret, c, 0, cpy);
+
+ if (cpy < buf.length)
+ list[0] = buf.slice(cpy);
+ else
+ list.shift();
+
+ c += cpy;
+ }
+ }
+ }
+
+ return ret;
+}
+
+function endReadable(stream) {
+ var state = stream._readableState;
+
+ // If we get here before consuming all the bytes, then that is a
+ // bug in node. Should never happen.
+ if (state.length > 0)
+ throw new Error('endReadable called on non-empty stream');
+
+ if (!state.endEmitted) {
+ state.ended = true;
+ processNextTick(endReadableNT, state, stream);
+ }
+}
+
+function endReadableNT(state, stream) {
+ // Check that we didn't get one last unshift.
+ if (!state.endEmitted && state.length === 0) {
+ state.endEmitted = true;
+ stream.readable = false;
+ stream.emit('end');
+ }
+}
+
+function forEach (xs, f) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ f(xs[i], i);
+ }
+}
+
+function indexOf (xs, x) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ if (xs[i] === x) return i;
+ }
+ return -1;
+}
diff --git a/node_modules/request/node_modules/readable-stream/lib/_stream_transform.js b/node_modules/request/node_modules/readable-stream/lib/_stream_transform.js
new file mode 100644
index 000000000..3675d18d9
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/lib/_stream_transform.js
@@ -0,0 +1,197 @@
+// a transform stream is a readable/writable stream where you do
+// something with the data. Sometimes it's called a "filter",
+// but that's not a great name for it, since that implies a thing where
+// some bits pass through, and others are simply ignored. (That would
+// be a valid example of a transform, of course.)
+//
+// While the output is causally related to the input, it's not a
+// necessarily symmetric or synchronous transformation. For example,
+// a zlib stream might take multiple plain-text writes(), and then
+// emit a single compressed chunk some time in the future.
+//
+// Here's how this works:
+//
+// The Transform stream has all the aspects of the readable and writable
+// stream classes. When you write(chunk), that calls _write(chunk,cb)
+// internally, and returns false if there's a lot of pending writes
+// buffered up. When you call read(), that calls _read(n) until
+// there's enough pending readable data buffered up.
+//
+// In a transform stream, the written data is placed in a buffer. When
+// _read(n) is called, it transforms the queued up data, calling the
+// buffered _write cb's as it consumes chunks. If consuming a single
+// written chunk would result in multiple output chunks, then the first
+// outputted bit calls the readcb, and subsequent chunks just go into
+// the read buffer, and will cause it to emit 'readable' if necessary.
+//
+// This way, back-pressure is actually determined by the reading side,
+// since _read has to be called to start processing a new chunk. However,
+// a pathological inflate type of transform can cause excessive buffering
+// here. For example, imagine a stream where every byte of input is
+// interpreted as an integer from 0-255, and then results in that many
+// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
+// 1kb of data being output. In this case, you could write a very small
+// amount of input, and end up with a very large amount of output. In
+// such a pathological inflating mechanism, there'd be no way to tell
+// the system to stop doing the transform. A single 4MB write could
+// cause the system to run out of memory.
+//
+// However, even in such a pathological case, only a single written chunk
+// would be consumed, and then the rest would wait (un-transformed) until
+// the results of the previous transformed chunk were consumed.
+
+'use strict';
+
+module.exports = Transform;
+
+var Duplex = require('./_stream_duplex');
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+util.inherits(Transform, Duplex);
+
+
+function TransformState(stream) {
+ this.afterTransform = function(er, data) {
+ return afterTransform(stream, er, data);
+ };
+
+ this.needTransform = false;
+ this.transforming = false;
+ this.writecb = null;
+ this.writechunk = null;
+}
+
+function afterTransform(stream, er, data) {
+ var ts = stream._transformState;
+ ts.transforming = false;
+
+ var cb = ts.writecb;
+
+ if (!cb)
+ return stream.emit('error', new Error('no writecb in Transform class'));
+
+ ts.writechunk = null;
+ ts.writecb = null;
+
+ if (data !== null && data !== undefined)
+ stream.push(data);
+
+ if (cb)
+ cb(er);
+
+ var rs = stream._readableState;
+ rs.reading = false;
+ if (rs.needReadable || rs.length < rs.highWaterMark) {
+ stream._read(rs.highWaterMark);
+ }
+}
+
+
+function Transform(options) {
+ if (!(this instanceof Transform))
+ return new Transform(options);
+
+ Duplex.call(this, options);
+
+ this._transformState = new TransformState(this);
+
+ // when the writable side finishes, then flush out anything remaining.
+ var stream = this;
+
+ // start out asking for a readable event once data is transformed.
+ this._readableState.needReadable = true;
+
+ // we have implemented the _read method, and done the other things
+ // that Readable wants before the first _read call, so unset the
+ // sync guard flag.
+ this._readableState.sync = false;
+
+ if (options) {
+ if (typeof options.transform === 'function')
+ this._transform = options.transform;
+
+ if (typeof options.flush === 'function')
+ this._flush = options.flush;
+ }
+
+ this.once('prefinish', function() {
+ if (typeof this._flush === 'function')
+ this._flush(function(er) {
+ done(stream, er);
+ });
+ else
+ done(stream);
+ });
+}
+
+Transform.prototype.push = function(chunk, encoding) {
+ this._transformState.needTransform = false;
+ return Duplex.prototype.push.call(this, chunk, encoding);
+};
+
+// This is the part where you do stuff!
+// override this function in implementation classes.
+// 'chunk' is an input chunk.
+//
+// Call `push(newChunk)` to pass along transformed output
+// to the readable side. You may call 'push' zero or more times.
+//
+// Call `cb(err)` when you are done with this chunk. If you pass
+// an error, then that'll put the hurt on the whole operation. If you
+// never call cb(), then you'll never get another chunk.
+Transform.prototype._transform = function(chunk, encoding, cb) {
+ throw new Error('not implemented');
+};
+
+Transform.prototype._write = function(chunk, encoding, cb) {
+ var ts = this._transformState;
+ ts.writecb = cb;
+ ts.writechunk = chunk;
+ ts.writeencoding = encoding;
+ if (!ts.transforming) {
+ var rs = this._readableState;
+ if (ts.needTransform ||
+ rs.needReadable ||
+ rs.length < rs.highWaterMark)
+ this._read(rs.highWaterMark);
+ }
+};
+
+// Doesn't matter what the args are here.
+// _transform does all the work.
+// That we got here means that the readable side wants more data.
+Transform.prototype._read = function(n) {
+ var ts = this._transformState;
+
+ if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
+ ts.transforming = true;
+ this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
+ } else {
+ // mark that we need a transform, so that any data that comes in
+ // will get processed, now that we've asked for it.
+ ts.needTransform = true;
+ }
+};
+
+
+function done(stream, er) {
+ if (er)
+ return stream.emit('error', er);
+
+ // if there's nothing in the write buffer, then that means
+ // that nothing more will ever be provided
+ var ws = stream._writableState;
+ var ts = stream._transformState;
+
+ if (ws.length)
+ throw new Error('calling transform done when ws.length != 0');
+
+ if (ts.transforming)
+ throw new Error('calling transform done when still transforming');
+
+ return stream.push(null);
+}
diff --git a/node_modules/request/node_modules/readable-stream/lib/_stream_writable.js b/node_modules/request/node_modules/readable-stream/lib/_stream_writable.js
new file mode 100644
index 000000000..b23295201
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/lib/_stream_writable.js
@@ -0,0 +1,520 @@
+// A bit simpler than readable streams.
+// Implement an async ._write(chunk, cb), and it'll handle all
+// the drain event emission and buffering.
+
+'use strict';
+
+module.exports = Writable;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+
+/*<replacement>*/
+var Buffer = require('buffer').Buffer;
+/*</replacement>*/
+
+Writable.WritableState = WritableState;
+
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+
+
+/*<replacement>*/
+var Stream;
+(function (){try{
+ Stream = require('st' + 'ream');
+}catch(_){}finally{
+ if (!Stream)
+ Stream = require('events').EventEmitter;
+}}())
+/*</replacement>*/
+
+var Buffer = require('buffer').Buffer;
+
+util.inherits(Writable, Stream);
+
+function nop() {}
+
+function WriteReq(chunk, encoding, cb) {
+ this.chunk = chunk;
+ this.encoding = encoding;
+ this.callback = cb;
+ this.next = null;
+}
+
+function WritableState(options, stream) {
+ var Duplex = require('./_stream_duplex');
+
+ options = options || {};
+
+ // object stream flag to indicate whether or not this stream
+ // contains buffers or objects.
+ this.objectMode = !!options.objectMode;
+
+ if (stream instanceof Duplex)
+ this.objectMode = this.objectMode || !!options.writableObjectMode;
+
+ // the point at which write() starts returning false
+ // Note: 0 is a valid value, means that we always return false if
+ // the entire buffer is not flushed immediately on write()
+ var hwm = options.highWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+ this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = ~~this.highWaterMark;
+
+ this.needDrain = false;
+ // at the start of calling end()
+ this.ending = false;
+ // when end() has been called, and returned
+ this.ended = false;
+ // when 'finish' is emitted
+ this.finished = false;
+
+ // should we decode strings into buffers before passing to _write?
+ // this is here so that some node-core streams can optimize string
+ // handling at a lower level.
+ var noDecode = options.decodeStrings === false;
+ this.decodeStrings = !noDecode;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // not an actual buffer we keep track of, but a measurement
+ // of how much we're waiting to get pushed to some underlying
+ // socket or file.
+ this.length = 0;
+
+ // a flag to see when we're in the middle of a write.
+ this.writing = false;
+
+ // when true all writes will be buffered until .uncork() call
+ this.corked = 0;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // a flag to know if we're processing previously buffered items, which
+ // may call the _write() callback in the same tick, so that we don't
+ // end up in an overlapped onwrite situation.
+ this.bufferProcessing = false;
+
+ // the callback that's passed to _write(chunk,cb)
+ this.onwrite = function(er) {
+ onwrite(stream, er);
+ };
+
+ // the callback that the user supplies to write(chunk,encoding,cb)
+ this.writecb = null;
+
+ // the amount that is being written when _write is called.
+ this.writelen = 0;
+
+ this.bufferedRequest = null;
+ this.lastBufferedRequest = null;
+
+ // number of pending user-supplied write callbacks
+ // this must be 0 before 'finish' can be emitted
+ this.pendingcb = 0;
+
+ // emit prefinish if the only thing we're waiting for is _write cbs
+ // This is relevant for synchronous Transform streams
+ this.prefinished = false;
+
+ // True if the error was already emitted and should not be thrown again
+ this.errorEmitted = false;
+}
+
+WritableState.prototype.getBuffer = function writableStateGetBuffer() {
+ var current = this.bufferedRequest;
+ var out = [];
+ while (current) {
+ out.push(current);
+ current = current.next;
+ }
+ return out;
+};
+
+(function (){try {
+Object.defineProperty(WritableState.prototype, 'buffer', {
+ get: require('util-deprecate')(function() {
+ return this.getBuffer();
+ }, '_writableState.buffer is deprecated. Use ' +
+ '_writableState.getBuffer() instead.')
+});
+}catch(_){}}());
+
+
+function Writable(options) {
+ var Duplex = require('./_stream_duplex');
+
+ // Writable ctor is applied to Duplexes, though they're not
+ // instanceof Writable, they're instanceof Readable.
+ if (!(this instanceof Writable) && !(this instanceof Duplex))
+ return new Writable(options);
+
+ this._writableState = new WritableState(options, this);
+
+ // legacy.
+ this.writable = true;
+
+ if (options) {
+ if (typeof options.write === 'function')
+ this._write = options.write;
+
+ if (typeof options.writev === 'function')
+ this._writev = options.writev;
+ }
+
+ Stream.call(this);
+}
+
+// Otherwise people can pipe Writable streams, which is just wrong.
+Writable.prototype.pipe = function() {
+ this.emit('error', new Error('Cannot pipe. Not readable.'));
+};
+
+
+function writeAfterEnd(stream, cb) {
+ var er = new Error('write after end');
+ // TODO: defer error events consistently everywhere, not just the cb
+ stream.emit('error', er);
+ processNextTick(cb, er);
+}
+
+// If we get something that is not a buffer, string, null, or undefined,
+// and we're not in objectMode, then that's an error.
+// Otherwise stream chunks are all considered to be of length=1, and the
+// watermarks determine how many objects to keep in the buffer, rather than
+// how many bytes or characters.
+function validChunk(stream, state, chunk, cb) {
+ var valid = true;
+
+ if (!(Buffer.isBuffer(chunk)) &&
+ typeof chunk !== 'string' &&
+ chunk !== null &&
+ chunk !== undefined &&
+ !state.objectMode) {
+ var er = new TypeError('Invalid non-string/buffer chunk');
+ stream.emit('error', er);
+ processNextTick(cb, er);
+ valid = false;
+ }
+ return valid;
+}
+
+Writable.prototype.write = function(chunk, encoding, cb) {
+ var state = this._writableState;
+ var ret = false;
+
+ if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (Buffer.isBuffer(chunk))
+ encoding = 'buffer';
+ else if (!encoding)
+ encoding = state.defaultEncoding;
+
+ if (typeof cb !== 'function')
+ cb = nop;
+
+ if (state.ended)
+ writeAfterEnd(this, cb);
+ else if (validChunk(this, state, chunk, cb)) {
+ state.pendingcb++;
+ ret = writeOrBuffer(this, state, chunk, encoding, cb);
+ }
+
+ return ret;
+};
+
+Writable.prototype.cork = function() {
+ var state = this._writableState;
+
+ state.corked++;
+};
+
+Writable.prototype.uncork = function() {
+ var state = this._writableState;
+
+ if (state.corked) {
+ state.corked--;
+
+ if (!state.writing &&
+ !state.corked &&
+ !state.finished &&
+ !state.bufferProcessing &&
+ state.bufferedRequest)
+ clearBuffer(this, state);
+ }
+};
+
+Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
+ // node::ParseEncoding() requires lower case.
+ if (typeof encoding === 'string')
+ encoding = encoding.toLowerCase();
+ if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64',
+'ucs2', 'ucs-2','utf16le', 'utf-16le', 'raw']
+.indexOf((encoding + '').toLowerCase()) > -1))
+ throw new TypeError('Unknown encoding: ' + encoding);
+ this._writableState.defaultEncoding = encoding;
+};
+
+function decodeChunk(state, chunk, encoding) {
+ if (!state.objectMode &&
+ state.decodeStrings !== false &&
+ typeof chunk === 'string') {
+ chunk = new Buffer(chunk, encoding);
+ }
+ return chunk;
+}
+
+// if we're already writing something, then just put this
+// in the queue, and wait our turn. Otherwise, call _write
+// If we return false, then we need a drain event, so set that flag.
+function writeOrBuffer(stream, state, chunk, encoding, cb) {
+ chunk = decodeChunk(state, chunk, encoding);
+
+ if (Buffer.isBuffer(chunk))
+ encoding = 'buffer';
+ var len = state.objectMode ? 1 : chunk.length;
+
+ state.length += len;
+
+ var ret = state.length < state.highWaterMark;
+ // we must ensure that previous needDrain will not be reset to false.
+ if (!ret)
+ state.needDrain = true;
+
+ if (state.writing || state.corked) {
+ var last = state.lastBufferedRequest;
+ state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);
+ if (last) {
+ last.next = state.lastBufferedRequest;
+ } else {
+ state.bufferedRequest = state.lastBufferedRequest;
+ }
+ } else {
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ }
+
+ return ret;
+}
+
+function doWrite(stream, state, writev, len, chunk, encoding, cb) {
+ state.writelen = len;
+ state.writecb = cb;
+ state.writing = true;
+ state.sync = true;
+ if (writev)
+ stream._writev(chunk, state.onwrite);
+ else
+ stream._write(chunk, encoding, state.onwrite);
+ state.sync = false;
+}
+
+function onwriteError(stream, state, sync, er, cb) {
+ --state.pendingcb;
+ if (sync)
+ processNextTick(cb, er);
+ else
+ cb(er);
+
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+}
+
+function onwriteStateUpdate(state) {
+ state.writing = false;
+ state.writecb = null;
+ state.length -= state.writelen;
+ state.writelen = 0;
+}
+
+function onwrite(stream, er) {
+ var state = stream._writableState;
+ var sync = state.sync;
+ var cb = state.writecb;
+
+ onwriteStateUpdate(state);
+
+ if (er)
+ onwriteError(stream, state, sync, er, cb);
+ else {
+ // Check if we're actually ready to finish, but don't emit yet
+ var finished = needFinish(state);
+
+ if (!finished &&
+ !state.corked &&
+ !state.bufferProcessing &&
+ state.bufferedRequest) {
+ clearBuffer(stream, state);
+ }
+
+ if (sync) {
+ processNextTick(afterWrite, stream, state, finished, cb);
+ } else {
+ afterWrite(stream, state, finished, cb);
+ }
+ }
+}
+
+function afterWrite(stream, state, finished, cb) {
+ if (!finished)
+ onwriteDrain(stream, state);
+ state.pendingcb--;
+ cb();
+ finishMaybe(stream, state);
+}
+
+// Must force callback to be called on nextTick, so that we don't
+// emit 'drain' before the write() consumer gets the 'false' return
+// value, and has a chance to attach a 'drain' listener.
+function onwriteDrain(stream, state) {
+ if (state.length === 0 && state.needDrain) {
+ state.needDrain = false;
+ stream.emit('drain');
+ }
+}
+
+
+// if there's something in the buffer waiting, then process it
+function clearBuffer(stream, state) {
+ state.bufferProcessing = true;
+ var entry = state.bufferedRequest;
+
+ if (stream._writev && entry && entry.next) {
+ // Fast case, write everything using _writev()
+ var buffer = [];
+ var cbs = [];
+ while (entry) {
+ cbs.push(entry.callback);
+ buffer.push(entry);
+ entry = entry.next;
+ }
+
+ // count the one we are adding, as well.
+ // TODO(isaacs) clean this up
+ state.pendingcb++;
+ state.lastBufferedRequest = null;
+ doWrite(stream, state, true, state.length, buffer, '', function(err) {
+ for (var i = 0; i < cbs.length; i++) {
+ state.pendingcb--;
+ cbs[i](err);
+ }
+ });
+
+ // Clear buffer
+ } else {
+ // Slow case, write chunks one-by-one
+ while (entry) {
+ var chunk = entry.chunk;
+ var encoding = entry.encoding;
+ var cb = entry.callback;
+ var len = state.objectMode ? 1 : chunk.length;
+
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ entry = entry.next;
+ // if we didn't call the onwrite immediately, then
+ // it means that we need to wait until it does.
+ // also, that means that the chunk and cb are currently
+ // being processed, so move the buffer counter past them.
+ if (state.writing) {
+ break;
+ }
+ }
+
+ if (entry === null)
+ state.lastBufferedRequest = null;
+ }
+ state.bufferedRequest = entry;
+ state.bufferProcessing = false;
+}
+
+Writable.prototype._write = function(chunk, encoding, cb) {
+ cb(new Error('not implemented'));
+};
+
+Writable.prototype._writev = null;
+
+Writable.prototype.end = function(chunk, encoding, cb) {
+ var state = this._writableState;
+
+ if (typeof chunk === 'function') {
+ cb = chunk;
+ chunk = null;
+ encoding = null;
+ } else if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (chunk !== null && chunk !== undefined)
+ this.write(chunk, encoding);
+
+ // .end() fully uncorks
+ if (state.corked) {
+ state.corked = 1;
+ this.uncork();
+ }
+
+ // ignore unnecessary end() calls.
+ if (!state.ending && !state.finished)
+ endWritable(this, state, cb);
+};
+
+
+function needFinish(state) {
+ return (state.ending &&
+ state.length === 0 &&
+ state.bufferedRequest === null &&
+ !state.finished &&
+ !state.writing);
+}
+
+function prefinish(stream, state) {
+ if (!state.prefinished) {
+ state.prefinished = true;
+ stream.emit('prefinish');
+ }
+}
+
+function finishMaybe(stream, state) {
+ var need = needFinish(state);
+ if (need) {
+ if (state.pendingcb === 0) {
+ prefinish(stream, state);
+ state.finished = true;
+ stream.emit('finish');
+ } else {
+ prefinish(stream, state);
+ }
+ }
+ return need;
+}
+
+function endWritable(stream, state, cb) {
+ state.ending = true;
+ finishMaybe(stream, state);
+ if (cb) {
+ if (state.finished)
+ processNextTick(cb);
+ else
+ stream.once('finish', cb);
+ }
+ state.ended = true;
+}
diff --git a/node_modules/request/node_modules/readable-stream/package.json b/node_modules/request/node_modules/readable-stream/package.json
new file mode 100644
index 000000000..12db721ff
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/package.json
@@ -0,0 +1,98 @@
+{
+ "_args": [
+ [
+ "readable-stream@~2.0.0",
+ "/Users/rebecca/code/npm/node_modules/request/node_modules/bl"
+ ]
+ ],
+ "_from": "readable-stream@>=2.0.0 <2.1.0",
+ "_id": "readable-stream@2.0.2",
+ "_inCache": true,
+ "_location": "/request/readable-stream",
+ "_nodeVersion": "2.3.0",
+ "_npmUser": {
+ "email": "calvin.metcalf@gmail.com",
+ "name": "cwmma"
+ },
+ "_npmVersion": "2.11.1",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "readable-stream",
+ "raw": "readable-stream@~2.0.0",
+ "rawSpec": "~2.0.0",
+ "scope": null,
+ "spec": ">=2.0.0 <2.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/request/bl"
+ ],
+ "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+ "_shasum": "bec81beae8cf455168bc2e5b2b31f5bcfaed9b1b",
+ "_shrinkwrap": null,
+ "_spec": "readable-stream@~2.0.0",
+ "_where": "/Users/rebecca/code/npm/node_modules/request/node_modules/bl",
+ "browser": {
+ "util": false
+ },
+ "bugs": {
+ "url": "https://github.com/nodejs/readable-stream/issues"
+ },
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "process-nextick-args": "~1.0.0",
+ "string_decoder": "~0.10.x",
+ "util-deprecate": "~1.0.1"
+ },
+ "description": "Streams3, a user-land copy of the stream library from iojs v2.x",
+ "devDependencies": {
+ "tap": "~0.2.6",
+ "tape": "~4.0.0",
+ "zuul": "~3.0.0"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "bec81beae8cf455168bc2e5b2b31f5bcfaed9b1b",
+ "tarball": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz"
+ },
+ "gitHead": "1a70134a71196eeabb5e27bc7580faaa68d30513",
+ "homepage": "https://github.com/nodejs/readable-stream#readme",
+ "keywords": [
+ "pipe",
+ "readable",
+ "stream"
+ ],
+ "license": "MIT",
+ "main": "readable.js",
+ "maintainers": [
+ {
+ "name": "isaacs",
+ "email": "isaacs@npmjs.com"
+ },
+ {
+ "name": "tootallnate",
+ "email": "nathan@tootallnate.net"
+ },
+ {
+ "name": "rvagg",
+ "email": "rod@vagg.org"
+ },
+ {
+ "name": "cwmma",
+ "email": "calvin.metcalf@gmail.com"
+ }
+ ],
+ "name": "readable-stream",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/readable-stream.git"
+ },
+ "scripts": {
+ "browser": "zuul --browser-name $BROWSER_NAME --browser-version $BROWSER_VERSION -- test/browser.js",
+ "test": "tap test/parallel/*.js"
+ },
+ "version": "2.0.2"
+}
diff --git a/node_modules/request/node_modules/readable-stream/passthrough.js b/node_modules/request/node_modules/readable-stream/passthrough.js
new file mode 100644
index 000000000..27e8d8a55
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/passthrough.js
@@ -0,0 +1 @@
+module.exports = require("./lib/_stream_passthrough.js")
diff --git a/node_modules/request/node_modules/readable-stream/readable.js b/node_modules/request/node_modules/readable-stream/readable.js
new file mode 100644
index 000000000..6222a5798
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/readable.js
@@ -0,0 +1,12 @@
+var Stream = (function (){
+ try {
+ return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify
+ } catch(_){}
+}());
+exports = module.exports = require('./lib/_stream_readable.js');
+exports.Stream = Stream || exports;
+exports.Readable = exports;
+exports.Writable = require('./lib/_stream_writable.js');
+exports.Duplex = require('./lib/_stream_duplex.js');
+exports.Transform = require('./lib/_stream_transform.js');
+exports.PassThrough = require('./lib/_stream_passthrough.js');
diff --git a/node_modules/request/node_modules/readable-stream/transform.js b/node_modules/request/node_modules/readable-stream/transform.js
new file mode 100644
index 000000000..5d482f078
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/transform.js
@@ -0,0 +1 @@
+module.exports = require("./lib/_stream_transform.js")
diff --git a/node_modules/request/node_modules/readable-stream/writable.js b/node_modules/request/node_modules/readable-stream/writable.js
new file mode 100644
index 000000000..e1e9efdf3
--- /dev/null
+++ b/node_modules/request/node_modules/readable-stream/writable.js
@@ -0,0 +1 @@
+module.exports = require("./lib/_stream_writable.js")
diff --git a/node_modules/request/package.json b/node_modules/request/package.json
index 61a35d2a2..ea04215bc 100644
--- a/node_modules/request/package.json
+++ b/node_modules/request/package.json
@@ -6,16 +6,27 @@
]
],
"_from": "request@>=2.0.0 <3.0.0",
- "_id": "request@2.58.0",
+ "_id": "request@2.60.0",
"_inCache": true,
"_location": "/request",
- "_nodeVersion": "0.12.4",
+ "_nodeVersion": "0.12.6",
"_npmUser": {
"email": "simeonvelichkov@gmail.com",
"name": "simov"
},
- "_npmVersion": "2.10.1",
- "_phantomChildren": {},
+ "_npmVersion": "2.11.2",
+ "_phantomChildren": {
+ "boom": "2.8.0",
+ "core-util-is": "1.0.1",
+ "cryptiles": "2.0.4",
+ "hoek": "2.14.0",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "process-nextick-args": "1.0.1",
+ "sntp": "1.0.9",
+ "string_decoder": "0.10.31",
+ "util-deprecate": "1.0.1"
+ },
"_requested": {
"name": "request",
"raw": "request@2",
@@ -28,8 +39,8 @@
"/node-gyp",
"/npm-registry-client"
],
- "_resolved": "https://registry.npmjs.org/request/-/request-2.58.0.tgz",
- "_shasum": "b5f49c0b94aab7fad388612a1fb6ad03b6cc1580",
+ "_resolved": "https://registry.npmjs.org/request/-/request-2.60.0.tgz",
+ "_shasum": "498820957fcdded1d37749069610c85f61a29f2d",
"_shrinkwrap": null,
"_spec": "request@2",
"_where": "/Users/rebecca/code/npm/node_modules/node-gyp",
@@ -42,21 +53,21 @@
},
"dependencies": {
"aws-sign2": "~0.5.0",
- "bl": "~0.9.0",
- "caseless": "~0.10.0",
+ "bl": "~1.0.0",
+ "caseless": "~0.11.0",
"combined-stream": "~1.0.1",
- "extend": "~2.0.1",
+ "extend": "~3.0.0",
"forever-agent": "~0.6.0",
"form-data": "~1.0.0-rc1",
"har-validator": "^1.6.1",
- "hawk": "~2.3.0",
+ "hawk": "~3.1.0",
"http-signature": "~0.11.0",
"isstream": "~0.1.1",
"json-stringify-safe": "~5.0.0",
- "mime-types": "~2.0.1",
+ "mime-types": "~2.1.2",
"node-uuid": "~1.4.0",
"oauth-sign": "~0.8.0",
- "qs": "~3.1.0",
+ "qs": "~4.0.0",
"stringstream": "~0.0.4",
"tough-cookie": ">=0.12.0",
"tunnel-agent": "~0.4.0"
@@ -85,13 +96,13 @@
},
"directories": {},
"dist": {
- "shasum": "b5f49c0b94aab7fad388612a1fb6ad03b6cc1580",
- "tarball": "http://registry.npmjs.org/request/-/request-2.58.0.tgz"
+ "shasum": "498820957fcdded1d37749069610c85f61a29f2d",
+ "tarball": "http://registry.npmjs.org/request/-/request-2.60.0.tgz"
},
"engines": {
"node": ">=0.8.0"
},
- "gitHead": "ab40f9e61f813f9cc68257c17621b7879561486c",
+ "gitHead": "af19cef3bc60e9151ffce5015d8ce3c0728d3aca",
"homepage": "https://github.com/request/request#readme",
"license": "Apache-2.0",
"main": "index.js",
@@ -132,5 +143,5 @@
"util",
"utility"
],
- "version": "2.58.0"
+ "version": "2.60.0"
}
diff --git a/node_modules/request/request.js b/node_modules/request/request.js
index c032ea8f6..f3f5dd915 100644
--- a/node_modules/request/request.js
+++ b/node_modules/request/request.js
@@ -31,6 +31,7 @@ var safeStringify = helpers.safeStringify
, toBase64 = helpers.toBase64
, defer = helpers.defer
, copy = helpers.copy
+ , version = helpers.version
, globalCookieJar = cookies.jar()
@@ -430,28 +431,24 @@ Request.prototype.init = function (options) {
self.elapsedTime = self.elapsedTime || 0
}
- if (self.body) {
- var length = 0
- if (!Buffer.isBuffer(self.body)) {
- if (Array.isArray(self.body)) {
- for (var i = 0; i < self.body.length; i++) {
- length += self.body[i].length
- }
- } else {
- self.body = new Buffer(self.body)
- length = self.body.length
- }
- } else {
- length = self.body.length
+ function setContentLength () {
+ if (!Buffer.isBuffer(self.body) && !Array.isArray(self.body)) {
+ self.body = new Buffer(self.body)
}
- if (length) {
- if (!self.hasHeader('content-length')) {
+ if (!self.hasHeader('content-length')) {
+ var length = (Array.isArray(self.body))
+ ? self.body.reduce(function (a, b) {return a + b.length}, 0)
+ : self.body.length
+ if (length) {
self.setHeader('content-length', length)
+ } else {
+ self.emit('error', new Error('Argument error, options.body.'))
}
- } else {
- self.emit('error', new Error('Argument error, options.body.'))
}
}
+ if (self.body) {
+ setContentLength()
+ }
if (options.oauth) {
self.oauth(options.oauth)
@@ -481,7 +478,16 @@ Request.prototype.init = function (options) {
if (options.agentClass) {
self.agentClass = options.agentClass
} else if (options.forever) {
- self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
+ var v = version()
+ // use ForeverAgent in node 0.10- only
+ if (v.major === 0 && v.minor <= 10) {
+ self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
+ } else {
+ self.agent = new self.httpModule.Agent({
+ keepAlive: true,
+ maxSockets: (options.pool && options.pool.maxSockets) || Infinity
+ })
+ }
} else {
self.agentClass = self.httpModule.Agent
}
@@ -541,6 +547,7 @@ Request.prototype.init = function (options) {
self._multipart.body.pipe(self)
}
if (self.body) {
+ setContentLength()
if (Array.isArray(self.body)) {
self.body.forEach(function (part) {
self.write(part)
@@ -566,7 +573,7 @@ Request.prototype.init = function (options) {
if (self._form && !self.hasHeader('content-length')) {
// Before ending the request, we had to compute the length of the whole form, asyncly
- self.setHeader(self._form.getHeaders())
+ self.setHeader(self._form.getHeaders(), true)
self._form.getLength(function (err, length) {
if (!err) {
self.setHeader('content-length', length)
@@ -1145,7 +1152,9 @@ Request.prototype.qs = function (q, clobber) {
Request.prototype.form = function (form) {
var self = this
if (form) {
- self.setHeader('content-type', 'application/x-www-form-urlencoded')
+ if (!/^application\/x-www-form-urlencoded\b/.test(self.getHeader('content-type'))) {
+ self.setHeader('content-type', 'application/x-www-form-urlencoded')
+ }
self.body = (typeof form === 'string')
? self._qs.rfc3986(form.toString('utf8'))
: self._qs.stringify(form).toString('utf8')