[
  {
    "path": ".browserslistrc",
    "content": "defaults, not ie 11\n"
  },
  {
    "path": ".commitlintrc.js",
    "content": "module.exports = {\n  extends: ['@commitlint/config-conventional']\n};\n"
  },
  {
    "path": ".dist.babelrc",
    "content": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"browsers\": [ \"defaults, not ie 11\" ]\n      }\n    }]\n  ],\n  \"sourceType\": \"script\",\n  \"sourceMaps\": \"inline\",\n  \"comments\": false\n}\n"
  },
  {
    "path": ".dist.eslintrc",
    "content": "{\n  \"extends\": [\"eslint:recommended\", \"plugin:compat/recommended\"],\n  \"env\": {\n    \"node\": false,\n    \"browser\": true,\n    \"amd\": true,\n    \"es6\": true\n  },\n  \"plugins\": [\"compat\"],\n  \"rules\": {\n    \"node/no-unsupported-features/es-builtins\": \"off\",\n    \"compat/compat\": \"error\",\n    \"no-console\": \"off\",\n    \"no-empty\": \"off\",\n    \"no-extra-semi\": \"off\",\n    \"no-func-assign\": \"off\",\n    \"no-undef\": \"off\",\n    \"no-unused-vars\": \"off\",\n    \"no-useless-escape\": \"off\",\n    \"no-obj-calls\": \"off\",\n    \"no-cond-assign\": \"off\",\n    \"no-redeclare\": \"off\",\n    \"node/no-exports-assign\": \"off\",\n    \"no-unsafe-finally\": \"off\",\n    \"complexity\": [\"error\", 10000],\n    \"max-statements\": \"off\",\n    \"no-constant-condition\": \"off\",\n    \"no-control-regex\": \"off\",\n    \"no-fallthrough\": \"off\",\n    \"operator-linebreak\": \"off\",\n    \"node/no-missing-require\": \"warn\"\n  },\n  \"globals\": {\n    \"regeneratorRuntime\": \"writable\"\n  },\n  \"settings\": {\n    \"polyfills\": [\n      \"WeakRef\",\n      \"BigInt\"\n    ]\n  }\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:node/recommended\"\n  ],\n  \"env\": {\n    \"node\": true,\n    \"browser\": true,\n    \"es6\": true\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 2021\n  },\n  \"overrides\": [\n    {\n      \"files\": \"test/**/*.js\",\n      \"env\": {\n        \"mocha\": true\n      },\n      \"rules\": {\n        \"no-prototype-builtins\": \"off\",\n        \"node/no-deprecated-api\": \"warn\",\n        \"node/no-extraneous-require\": \"warn\",\n        \"no-unused-vars\": \"warn\",\n        \"node/no-missing-require\": \"warn\"\n      }\n    }\n  ],\n  \"rules\": {\n    \"node/no-unsupported-features/node-builtins\": \"off\",\n    \"node/no-unsupported-features/es-syntax\": \"off\",\n    \"node/no-exports-assign\": \"off\",\n    \"no-unused-vars\": \"warn\"\n  },\n  \"globals\": {\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non: [push, pull_request]\n\nenv:\n  SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}\n  SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}\n\npermissions:\n  contents: read #  to fetch code (actions/checkout)\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n       include:\n        - node-version: 18.x\n        - node-version: 20.x\n        - node-version: 22.x\n        - node-version: 24.x\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install Node - ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'npm'\n      - name: Install dependencies\n        run: npm ci\n      - name: Build\n        run: npm run build\n      - name: Test On Node ${{ matrix.node-version }}\n        env:\n          BROWSER: ${{ matrix.test-on-brower }}\n          HTTP2_TEST_DISABLED: ${{ matrix.http2-test-disabled }}\n          OLD_NODE_TEST: ${{ matrix.test-on-old-node }}\n        run: |\n          if [ \"$OLD_NODE_TEST\" = \"1\" ]; then\n            make test\n          else\n            npm run lint\n            make test\n          fi\n      - name: Coverage On Node ${{ matrix.node-version }}\n        run: npm run coverage\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v4\n"
  },
  {
    "path": ".gitignore",
    "content": ".vscode\nbuild\nlib-cov\ncoverage.html\n.DS_Store\nnode_modules\n*.sock\ntest.js\ncomponents\ntest/node/fixtures/tmp.json\n.idea\nsuperagent.js\n*.log\ncoverage\n.nyc_output\nlib\ndist\n*.swp\nyarn.lock\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "npx commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "npx lint-staged\n"
  },
  {
    "path": ".lib.babelrc",
    "content": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"node\": \"14.18.0\",\n        \"browsers\": [ \"defaults, not ie 11\" ]\n      }\n    }]\n  ],\n  \"sourceMaps\": \"inline\"\n}\n"
  },
  {
    "path": ".lib.eslintrc",
    "content": "{\n  \"extends\": [\"eslint:recommended\", \"plugin:node/recommended\"],\n  \"env\": {\n    \"browser\": true\n  },\n  \"rules\": {\n    \"node/no-unsupported-features/es-builtins\": [\"error\", {\n      \"version\": \">=6.4.0\",\n      \"ignores\": [\n      ]\n    }],\n    \"node/no-deprecated-api\": \"off\",\n    \"no-console\": \"off\",\n    \"no-unused-vars\": \"off\",\n    \"no-empty\": \"off\",\n    \"no-func-assign\": \"off\",\n    \"no-global-assign\": [\"error\", {\"exceptions\": [\"exports\"]}],\n    \"no-fallthrough\": \"off\",\n    \"no-constant-condition\": \"off\",\n    \"node/no-exports-assign\": \"off\",\n    \"no-unsafe-finally\": \"off\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [ \"lib/client.js\" ],\n      \"globals\": {\n      }\n    },\n    {\n      \"files\": [ \"lib/node/http2wrapper.js\" ],\n      \"rules\": {\n        \"node/no-unsupported-features/es-builtins\": \"off\",\n        \"node/no-unsupported-features/node-builtins\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".lintstagedrc.js",
    "content": "module.exports = {\n  \"*.md\": filenames => filenames.map(filename => `remark ${filename} -qfo`),\n  '*.js': 'xo --fix'\n};\n"
  },
  {
    "path": ".npmrc",
    "content": "package-lock=true\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  singleQuote: true,\n  bracketSpacing: true,\n  trailingComma: 'none'\n};\n"
  },
  {
    "path": ".remarkignore",
    "content": "CONTRIBUTING.md\nHISTORY.md\ndocs\n"
  },
  {
    "path": ".remarkrc.js",
    "content": "module.exports = {\n  plugins: ['preset-github']\n};\n"
  },
  {
    "path": ".test.babelrc",
    "content": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"node\": \"14.18.0\",\n        \"browsers\": [ \"defaults, not ie 11\" ]\n      }\n    }]\n  ],\n  \"plugins\": [\n    [\"@babel/transform-runtime\"]\n  ],\n  \"parserOpts\": {\n    \"allowReturnOutsideFunction\": true\n  },\n  \"sourceMaps\": \"inline\"\n}\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: node_js\nnode_js:\n  - '18'\n  - '16'\n  - '14'\nafter_success: npm run coverage\n\nenv:\n  global:\n    - SAUCE_USERNAME='shtylman-superagent'\n    - SAUCE_ACCESS_KEY='39a45464-cb1d-4b8d-aa1f-83c7c04fa673'\n"
  },
  {
    "path": ".xo-config.js",
    "content": "module.exports = {\n\tprettier: true,\n\tspace: true,\n\tnodeVersion: false,\n\textends: [\n\t\t'xo-lass',\n\t],\n\tenvs: [\n\t\t'node',\n\t\t'browser',\n\t],\n\toverrides: [\n\t\t{\n\t\t\tfiles: 'test/**/*.js',\n\t\t\tenvs: [\n\t\t\t\t'mocha',\n\t\t\t],\n\t\t\trules: {\n\t\t\t\t'block-scoped-var': 'warn',\n\t\t\t\tcomplexity: 'warn',\n\t\t\t\t'default-case': 'warn',\n\t\t\t\teqeqeq: 'warn',\n\t\t\t\t'func-name-matching': 'warn',\n\t\t\t\t'func-names': 'warn',\n\t\t\t\t'guard-for-in': 'warn',\n\t\t\t\t'handle-callback-err': 'warn',\n\t\t\t\t'import/no-extraneous-dependencies': 'warn',\n\t\t\t\t'import/no-unassigned-import': 'warn',\n\t\t\t\t'import/order': 'warn',\n\t\t\t\t'max-nested-callbacks': 'warn',\n\t\t\t\t'new-cap': 'warn',\n\t\t\t\t'no-eq-null': 'warn',\n\t\t\t\t'no-extend-native': 'warn',\n\t\t\t\t'no-implicit-coercion': 'warn',\n\t\t\t\t'no-multi-assign': 'warn',\n\t\t\t\t'no-negated-condition': 'off',\n\t\t\t\t'no-prototype-builtins': 'warn',\n\t\t\t\t'no-redeclare': 'warn',\n\t\t\t\t'no-undef': 'warn',\n\t\t\t\t'no-unused-expressions': 'warn',\n\t\t\t\t'no-unused-vars': 'warn',\n\t\t\t\t'no-use-extend-native/no-use-extend-native': 'warn',\n\t\t\t\t'no-useless-escape': 'warn',\n\t\t\t\t'no-var': 'warn',\n\t\t\t\t'no-void': 'warn',\n\t\t\t\t'n/no-deprecated-api': 'warn',\n\t\t\t\t'prefer-rest-params': 'warn',\n\t\t\t\t'prefer-spread': 'warn',\n\t\t\t\t'unicorn/filename-case': 'warn',\n\t\t\t\t'valid-jsdoc': 'warn',\n\t\t\t\t'n/no-path-concat': 'warn',\n\t\t\t\t'unicorn/no-empty-file': 'warn',\n\t\t\t\t'unicorn/expiring-todo-comments': 'off',\n\t\t\t\t'n/prefer-global/buffer': 'off',\n\t\t\t\t'n/prefer-global/process': 'off',\n\t\t\t},\n\t\t},\n\t],\n\trules: {\n\t\t'unicorn/prevent-abbreviations': [\n\t\t\t'warn',\n\t\t\t{\n\t\t\t\treplacements: {\n\t\t\t\t\tres: false,\n\t\t\t\t\targs: false,\n\t\t\t\t\tfn: false,\n\t\t\t\t\terr: false,\n\t\t\t\t\te: false,\n\t\t\t\t\ti: false,\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t'no-bitwise': 'warn',\n\t\t'n/prefer-global/buffer': 'off',\n\t\t'n/prefer-global/process': 'off',\n\t\t'unicorn/no-new-array': 'warn',\n\t\t'unicorn/no-this-assignment': 'warn',\n\t\t'unicorn/prefer-spread': 'warn',\n\t\t'unicorn/catch-error-name': 'warn',\n\t\t'unicorn/prefer-code-point': 'warn',\n\t\t'n/no-unsupported-features': [\n\t\t\t'error',\n\t\t\t{\n\t\t\t\tversion: 8,\n\t\t\t\tignores: [\n\t\t\t\t\t'syntax',\n\t\t\t\t],\n\t\t\t},\n\t\t],\n    'unicorn/prefer-optional-catch-binding': 'off',\n    'no-unused-vars': 'off',\n    'unicorn/expiring-todo-comments': 'off'\n\t},\n\tglobals: [],\n};\n"
  },
  {
    "path": ".zuul.yml",
    "content": "ui: mocha-bdd\nserver: ./test/support/server.js\ntunnel_host: http://focusaurus.com\nbrowsers:\n  - name: chrome\n    version: latest\n  - name: firefox\n    version: latest\n  - name: safari\n    version: latest\n  - name: ie\n    version: 9..latest\nbrowserify:\n  - transform:\n      name: babelify\n      configFile: './.dist.babelrc'\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "When submitting a PR, your chance of acceptance increases if you do the following:\n\n* Code style is consistent with existing in the file.\n* Tests are passing (client and server).\n* You add a test for the failing issue you are fixing.\n* Code changes are focused on the area of discussion.\n* Do not rebuild the distribution files or increment version numbers.\n"
  },
  {
    "path": "HISTORY.md",
    "content": "# This HISTORY log is deprecated\n\nPlease see [GitHub releases page](https://github.com/ladjs/superagent/releases) for the current changelog.\n\n# 4.1.0 (2018-12-26)\n\n * `.connect()` IP/DNS override option (Kornel)\n * `.trustLocalhost()` option for allowing broken HTTPS on `localhost`\n * `.abort()` used with promises rejects the promise.\n\n# 4.0.0 (2018-11-17)\n\n## Breaking changes\n\n* Node.js v4 has reached it's end of life, so we no longer support it. It's v6+ or later. We recommend Node.js 10.\n* We now use ES6 in the browser code, too.\n  * If you're using Browserify or Webpack to package code for Internet Explorer, you will also have to use Babel.\n  * The pre-built node_modules/superagent.js is still ES5-compatible.\n* `.end(…)` returns `undefined` instead of the request. If you need the request object after calling `.end()` (and you probably don't), save it in a variable and call `request.end(…)`. Consider not using `.end()` at all, and migrating to promises by calling `.then()` instead.\n* In Node, responses with unknown MIME type are buffered by default. To get old behavior, if you use custom _unbuffered_ parsers, add `.buffer(false)` to requests or set `superagent.buffer[yourMimeType] = false`.\n* Invalid uses of `.pipe()` throw.\n\n\n## Minor changes\n\n* Throw if `req.abort().end()` is called\n* Throw if using unsupported mix of send and field\n* Reject `.end()` promise on all error events (Kornel Lesiński)\n* Set `https.servername` from the `Host` header (Kornel Lesiński)\n* Leave backticks unencoded in query strings where possible (Ethan Resnick)\n* Update node-mime to 2.x (Alexey Kucherenko)\n* Allow default buffer settings based on response-type (shrey)\n* `response.buffered` is more accurate.\n\n# 3.8.3 (2018-04-29)\n\n* Add flags for 201 & 422 responses (Nikhil Fadnis)\n* Emit progress event while uploading Node `Buffer` via send method (Sergey Akhalkov)\n* Fixed setting correct cookies for redirects (Damien Clark)\n* Replace .catch with ['catch'] for IE9 Support (Miguel Stevens)\n\n# 3.8.2 (2017-12-09)\n\n* Fixed handling of exceptions thrown from callbacks\n* Stricter matching of `+json` MIME types.\n\n# 3.8.1 (2017-11-08)\n\n* Clear authorization header on cross-domain redirect\n\n# 3.8.0\n\n* Added support for \"globally\" defined headers and event handlers via `superagent.agent()`. It now remembers default settings for all its requests.\n* Added optional callback to `.retry()` (Alexander Murphy)\n* Unified auth args handling in node/browser (Edmundo Alvarez)\n* Fixed error handling in zlib pipes (Kornel)\n* Documented that 3xx status codes are errors (Mickey Reiss)\n\n# 3.7.0 (2017-10-17)\n\n* Limit maximum response size. Prevents zip bombs (Kornel)\n* Catch and pass along errors in `.ok()` callback (Jeremy Ruppel)\n* Fixed parsing of XHR headers without a newline (nsf)\n\n# 3.6.2 (2017-10-02)\n\n* Upgrade MIME type dependency to a newer, secure version\n* Recognize PDF MIME as binary\n* Fix for error in subsequent require() calls (Steven de Salas)\n\n# 3.6.0 (2017-08-20)\n\n* Support disabling TCP_NODELAY option ([#1240](https://github.com/ladjs/superagent/issues/1240)) (xiamengyu)\n* Send payload in query string for GET and HEAD shorthand API (Peter Lyons)\n* Support passphrase with pfx certificate (Paul Westerdale (ABRS Limited))\n* Documentation improvements (Peter Lyons)\n* Fixed duplicated query string params ([#1200](https://github.com/ladjs/superagent/issues/1200)) (Kornel)\n\n# 3.5.1 (2017-03-18)\n\n* Allow crossDomain errors to be retried ([#1194](https://github.com/ladjs/superagent/issues/1194)) (Michael Olson)\n* Read responseType property from the correct object (Julien Dupouy)\n* Check for ownProperty before adding header (Lucas Vieira)\n\n# 3.5.0 (2017-02-23)\n\n* Add errno to distinguish between request timeout and body download timeout ([#1184](https://github.com/ladjs/superagent/issues/1184)) (Kornel Lesiński)\n* Warn about bogus timeout options ([#1185](https://github.com/ladjs/superagent/issues/1185)) (Kornel Lesiński)\n\n# 3.4.4 (2017-02-17)\n\n* Treat videos like images (Kornel Lesiński)\n* Avoid renaming module (Kornel Lesiński)\n\n# 3.4.3 (2017-02-14)\n\n* Fixed being able to define own parsers when their mime type starts with `text/` (Damien Clark)\n* `withCredentials(false)` (Andy Woods)\n* Use `formData.on` instead of `.once` (Kornel Lesiński)\n* Ignore `attach(\"file\",null)` (Kornel Lesiński)\n\n# 3.4.1 (2017-01-29)\n\n* Allow `retry()` and `retry(0)` (Alexander Pope)\n* Allow optional body/data in DELETE requests (Alpha Shuro)\n* Fixed query string on retried requests (Kornel Lesiński)\n\n# 3.4.0 (2017-01-25)\n\n* New `.retry(n)` method and `err.retries` (Alexander Pope)\n* Docs for HTTPS request (Jun Wan Goh)\n\n# 3.3.1 (2016-12-17)\n\n* Fixed \"double callback bug\" warning on timeouts of gzipped responses\n\n# 3.3.0 (2016-12-14)\n\n* Added `.ok(callback)` that allows customizing which responses are errors (Kornel Lesiński)\n* Added `.responseType()` to Node version (Kornel Lesiński)\n* Added `.parse()` to browser version (jakepearson)\n* Fixed parse error when using `responseType('blob')` (Kornel Lesiński)\n\n# 3.2.0 (2016-12-11)\n\n* Added `.timeout({response:ms})`, which allows limiting maximum response time independently from total download time (Kornel Lesiński)\n* Added warnings when `.end()` is called more than once (Kornel Lesiński)\n* Added `response.links` to browser version (Lukas Eipert)\n* `btoa` is no longer required in IE9 (Kornel Lesiński)\n* Fixed `.sortQuery()` on URLs without query strings (Kornel Lesiński)\n* Refactored common response code into `ResponseBase` (Lukas Eipert)\n\n# 3.1.0 (2016-11-28)\n\n* Added `.sortQuery()` (vicanso)\n* Added support for arrays and bools in `.field()` (Kornel Lesiński)\n* Made `superagent.Request` subclassable without need to patch all static methods (Kornel Lesiński)\n\n# 3.0.0 (2016-11-19)\n\n* Dropped support for Node 0.x. Please upgrade to at least Node 4.\n* Dropped support for componentjs (Damien Caselli)\n* Removed deprecated `.part()`/`superagent.Part` APIs.\n* Removed unreliable `.body` property on internal response object used by unbuffered parsers.\n  Note: the normal `response.body` is unaffected.\n* Multiple `.send()` calls mixing `Buffer`/`Blob` and JSON data are not possible and will now throw instead of messing up the data.\n* Improved `.send()` data object type check (Fernando Mendes)\n* Added common prototype for Node and browser versions (Andreas Helmberger)\n* Added `http+unix:` schema to support Unix sockets (Yuki KAN)\n* Added full `attach` options parameter in the Node version (Lapo Luchini)\n* Added `pfx` TLS option with new `pfx()` method. (Reid Burke)\n* Internally changed `.on` to `.once` to prevent possible memory leaks (Matt Blair)\n* Made all errors reported as an event (Kornel Lesiński)\n\n# 2.3.0 (2016-09-20)\n\n* Enabled `.field()` to handle objects (Affan Shahid)\n* Added authentication with client certificates (terusus)\n* Added `.catch()` for more Promise-like interface (Maxim Samoilov, Kornel Lesiński)\n* Silenced errors from incomplete gzip streams for compatibility with web browsers (Kornel Lesiński)\n* Fixed `event.direction` in uploads (Kornel Lesiński)\n* Fixed returned value of overwritten response object's `on()` method (Juan Dopazo)\n\n# 2.2.0 (2016-08-13)\n\n* Added `timedout` property to node Request instance (Alexander Pope)\n* Unified `null` querystring values in node and browser environments. (George Chung)\n\n# 2.1.0 (2016-06-14)\n\n* Refactored async parsers. Now the `end` callback waits for async parsers to finish (Kornel Lesiński)\n* Errors thrown in `.end()` callback don't cause the callback to be called twice (Kornel Lesiński)\n* Added `headers` to `toJSON()` (Tao)\n\n# 2.0.0 (2016-05-29)\n\n\n## Breaking changes\n\nBreaking changes are in rarely used functionality, so we hope upgrade will be smooth for most users.\n\n* Browser: The `.parse()` method has been renamed to `.serialize()` for consistency with NodeJS version.\n* Browser: Query string keys without a value used to be parsed as `'undefined'`, now their value is `''` (empty string) (shura, Kornel Lesiński).\n* NodeJS: The `redirect` event is called after new query string and headers have been set and is allowed to override the request URL (Kornel Lesiński)\n* `.then()` returns a real `Promise`. Note that use of superagent with promises now requires a global `Promise` object.\n  If you target Internet Explorer or Node 0.10, you'll need `require('es6-promise').polyfill()` or similar.\n* Upgraded all dependencies (Peter Lyons)\n* Renamed properties documented as `@api private` to have `_prefixed` names (Kornel Lesiński)\n\n\n## Probably not breaking changes:\n\n* Extracted common functions to request-base (Peter Lyons)\n* Fixed race condition in pipe tests (Peter Lyons)\n* Handle `FormData` error events (scriptype)\n* Fixed wrong jsdoc of Request#attach (George Chung)\n* Updated and improved tests (Peter Lyons)\n* `request.head()` supports `.redirects(5)` call (Kornel Lesiński)\n* `response` event is also emitted when using `.pipe()`\n\n# 1.8.2 (2016-03-20)\n\n* Fixed handling of HTTP status 204 with content-encoding: gzip (Andrew Shelton)\n* Handling of FormData error events (scriptype)\n* Fixed parsing of `vnd+json` MIME types (Kornel Lesiński)\n* Aliased browser implementation of `.parse()` as `.serialize()` for forward compatibility\n\n# 1.8.1 (2016-03-14)\n\n* Fixed form-data incompatibility with IE9\n\n# 1.8.0 (2016-03-09)\n\n* Extracted common code into request-base class (Peter Lyons)\n  * It does not affect the public API, but please let us know if you notice any plugins/subclasses breaking!\n* Added option `{type:'auto'}` to `auth` method, which enables browser-native auth types (Jungle, Askar Yusupov)\n* Added `responseType()` to set XHR `responseType` (chris)\n* Switched to form-data for browserify-compatible `FormData` (Peter Lyons)\n* Added `statusCode` to error response when JSON response is malformed (mattdell)\n* Prevented TCP port conflicts in all tests (Peter Lyons)\n* Updated form-data dependency\n\n# 1.7.2 (2016-01-26)\n\n* Fix case-sensitivity of header fields introduced by [`a4ddd6a`](https://github.com/ladjs/superagent/commit/a4ddd6a). (Edward J. Jinotti)\n* bump extend dependency, as former version did not contain any license information (Lukas Eipert)\n\n# 1.7.1 (2016-01-21)\n\n* Fixed a conflict with express when using npm 3.x (Glenn)\n* Fixed redirects after a multipart/form-data POST request (cyclist2)\n\n# 1.7.0 (2016-01-18)\n\n* When attaching files, read default filename from the `File` object (JD Isaacks)\n* Add `direction` property to `progress` events (Joseph Dykstra)\n* Update component-emitter & formidable (Kornel Lesiński)\n* Don't re-encode query string needlessly (Ruben Verborgh)\n* ensure querystring is appended when doing `stream.pipe(request)` (Keith Grennan)\n* change set header function, not call `this.request()` until call `this.end()` (vicanso)\n* Add no-op `withCredentials` to Node API (markdalgleish)\n* fix `delete` breaking on ie8 (kenjiokabe)\n* Don't let request error override responses (Clay Reimann)\n* Increased number of tests shared between node and client (Kornel Lesiński)\n\n# 1.6.0/1.6.1 (2015-12-09)\n\n* avoid misleading CORS error message\n* added 'progress' event on file/form upload in Node (Olivier Lalonde)\n* return raw response if the response parsing fails (Rei Colina)\n* parse content-types ending with `+json` as JSON (Eiryyy)\n* fix to avoid throwing errors on aborted requests (gjurgens)\n* retain cookies on redirect when hosts match (Tom Conroy)\n* added Bower manifest (Johnny Freeman)\n* upgrade to latest cookiejar (Andy Burke)\n\n# 1.5.0 (2015-11-30)\n\n* encode array values as `key=1&key=2&key=3` etc... (aalpern, Davis Kim)\n* avoid the error which is omitted from 'socket hang up'\n* faster JSON parsing, handling of zlib errors (jbellenger)\n* fix IE11 sends 'undefined' string if data was undefined (Vadim Goncharov)\n* alias `del()` method as `delete()` (Aaron Krause)\n* revert Request#parse since it was actually Response#parse\n\n# 1.4.0 (2015-09-14)\n\n* add Request#parse method to client library\n* add missing statusCode in client response\n* don't apply JSON heuristics if a valid parser is found\n* fix detection of root object for webworkers\n\n# 1.3.0 (2015-08-05)\n\n* fix incorrect content-length of data set to buffer\n* serialize request data takes into account charsets\n* add basic promise support via a `then` function\n\n# 1.2.0 (2015-04-13)\n\n* add progress events to downlodas\n* make usable in webworkers\n* add support for 308 redirects\n* update node-form-data dependency\n* update to work in react native\n* update node-mime dependency\n\n# 1.1.0 (2015-03-13)\n\n* Fix responseType checks without xhr2 and ie9 tests (rase-)\n* errors have .status and .response fields if applicable (defunctzombie)\n* fix end callback called before saving cookies (rase-)\n\n# 1.0.0 / 2015-03-08\n\n* All non-200 responses are treated as errors now. (The callback is called with an error when the response has a status &lt; 200 or >= 300 now. In previous versions this would not have raised an error and the client would have to check the `res` object. See [#283](https://github.com/ladjs/superagent/issues/283).\n* keep timeouts intact across redirects (hopkinsth)\n* handle falsy json values (themaarten)\n* fire response events in browser version (Schoonology)\n* getXHR exported in client version (KidsKilla)\n* remove arity check on `.end()` callbacks (defunctzombie)\n* avoid setting content-type for host objects (rexxars)\n* don't index array strings in querystring (travisjeffery)\n* fix pipe() with redirects (cyrilis)\n* add xhr2 file download (vstirbu)\n* set default response type to text/plain if not specified (warrenseine)\n\n# 0.21.0 / 2014-11-11\n\n* Trim text before parsing json (gjohnson)\n* Update tests to express 4 (gaastonsr)\n* Prevent double callback when error is thrown (pgn-vole)\n* Fix missing clearTimeout (nickdima)\n* Update debug (TooTallNate)\n\n# 0.20.0 / 2014-10-02\n\n* Add toJSON() to request and response instances. (yields)\n* Prevent HEAD requests from getting parsed. (gjohnson)\n* Update debug. (TooTallNate)\n\n# 0.19.1 / 2014-09-24\n\n* Fix basic auth issue when password is falsey value. (gjohnson)\n\n# 0.19.0 / 2014-09-24\n\n* Add unset() to browser. (shesek)\n* Prefer XHR over ActiveX. (omeid)\n* Catch parse errors. (jacwright)\n* Update qs dependency. (wercker)\n* Add use() to node. (Financial-Times)\n* Add response text to errors. (yields)\n* Don't send empty cookie headers. (undoZen)\n* Don't parse empty response bodies. (DveMac)\n* Use hostname when setting cookie host. (prasunsultania)\n\n# 0.18.2 / 2014-07-12\n\n* Handle parser errors. (kof)\n* Ensure not to use default parsers when there is a user defined one. (kof)\n\n# 0.18.1 / 2014-07-05\n\n* Upgrade cookiejar dependency (juanpin)\n* Support image mime types (nebulade)\n* Make .agent chainable (kof)\n* Upgrade debug (TooTallNate)\n* Fix docs (aheckmann)\n\n# 0.18.0 / 2014-04-29\n\n* Use \"form-data\" module for the multipart/form-data implementation. (TooTallNate)\n* Add basic `field()` and `attach()` functions for HTML5 FormData. (TooTallNate)\n* Deprecate `part()`. (TooTallNate)\n* Set default user-agent header. (bevacqua)\n* Add `unset()` method for removing headers. (bevacqua)\n* Update cookiejar. (missinglink)\n* Fix response error formatting. (shesek)\n\n# 0.17.0 / 2014-03-06\n\n* supply uri malformed error to the callback (yields)\n* add request event (yields)\n* allow simple auth (yields)\n* add request event (yields)\n* switch to component/reduce (visionmedia)\n* fix part content-disposition (mscdex)\n* add browser testing via zuul (defunctzombie)\n* adds request.use() (johntron)\n\n# 0.16.0 / 2014-01-07\n\n* remove support for 0.6 (superjoe30)\n* fix CORS withCredentials (wejendorp)\n* add \"test\" script (superjoe30)\n* add request .accept() method (nickl-)\n* add xml to mime types mappings (nickl-)\n* fix parse body error on HEAD requests (gjohnson)\n* fix documentation typos (matteofigus)\n* fix content-type + charset (bengourley)\n* fix null values on query parameters (cristiandouce)\n\n# 0.15.7 / 2013-10-19\n\n* pin should.js to 1.3.0 due to breaking change in 2.0.x\n* fix browserify regression\n\n# 0.15.5 / 2013-10-09\n\n* add browser field to support browserify\n* fix .field() value number support\n\n# 0.15.4 / 2013-07-09\n\n* node: add a Request#agent() function to set the http Agent to use\n\n# 0.15.3 / 2013-07-05\n\n* fix .pipe() unzipping on more recent nodes. Closes [#240](https://github.com/ladjs/superagent/issues/240)\n* fix passing an empty object to .query() no longer appends \"?\"\n* fix formidable error handling\n* update formidable\n\n# 0.15.2 / 2013-07-02\n\n* fix: emit 'end' when piping.\n\n# 0.15.1 / 2013-06-26\n\n* add try/catch around parseLinks\n\n# 0.15.0 / 2013-06-25\n\n* make `Response#toError()` have a more meaningful `message`\n\n# 0.14.9 / 2013-06-15\n\n* add debug()s to the node client\n* add .abort() method to node client\n\n# 0.14.8 / 2013-06-13\n\n* set .agent = false always\n* remove X-Requested-With. Closes [#189](https://github.com/ladjs/superagent/issues/189)\n\n# 0.14.7 / 2013-06-06\n\n* fix unzip error handling\n\n# 0.14.6 / 2013-05-23\n\n* fix HEAD unzip bug\n\n# 0.14.5 / 2013-05-23\n\n* add flag to ensure the callback is **never** invoked twice\n\n# 0.14.4 / 2013-05-22\n\n* add superagent.js build output\n* update qs\n* update emitter-component\n* revert \"add browser field to support browserify\" see [GH-221](https://github.com/ladjs/superagent/issues/221)\n\n# 0.14.3 / 2013-05-18\n\n* add browser field to support browserify\n\n# 0.14.2/ 2013-05-07\n\n* add host object check to fix serialization of File/Blobs etc as json\n\n# 0.14.1 / 2013-04-09\n\n* update qs\n\n# 0.14.0 / 2013-04-02\n\n* add client-side basic auth\n* fix retaining of .set() header field case\n\n# 0.13.0 / 2013-03-13\n\n* add progress events to client\n* add simple example\n* add res.headers as alias of res.header for browser client\n* add res.get(field) to node/client\n\n# 0.12.4 / 2013-02-11\n\n* fix get content-type even if can't get other headers in firefox. fixes [#181](https://github.com/ladjs/superagent/issues/181)\n\n# 0.12.3 / 2013-02-11\n\n* add quick \"progress\" event support\n\n# 0.12.2 / 2013-02-04\n\n* add test to check if response acts as a readable stream\n* add ReadableStream in the Response prototype.\n* add test to assert correct redirection when the host changes in the location header.\n* add default Accept-Encoding. Closes [#155](https://github.com/ladjs/superagent/issues/155)\n* fix req.pipe() return value of original stream for node parity. Closes [#171](https://github.com/ladjs/superagent/issues/171)\n* remove the host header when cleaning headers to properly follow the redirection.\n\n# 0.12.1 / 2013-01-10\n\n* add x-domain error handling\n\n# 0.12.0 / 2013-01-04\n\n* add header persistence on redirects\n\n# 0.11.0 / 2013-01-02\n\n* add .error Error object. Closes [#156](https://github.com/ladjs/superagent/issues/156)\n* add forcing of res.text removal for FF HEAD responses. Closes [#162](https://github.com/ladjs/superagent/issues/162)\n* add reduce component usage. Closes [#90](https://github.com/ladjs/superagent/issues/90)\n* move better-assert dep to development deps\n\n# 0.10.0 / 2012-11-14\n\n* add req.timeout(ms) support for the client\n\n# 0.9.10 / 2012-11-14\n\n* fix client-side .query(str) support\n\n# 0.9.9 / 2012-11-14\n\n* add .parse(fn) support\n* fix socket hangup with dates in querystring. Closes [#146](https://github.com/ladjs/superagent/issues/146)\n* fix socket hangup \"error\" event when a callback of arity 2 is provided\n\n# 0.9.8 / 2012-11-03\n\n* add emission of error from `Request#callback()`\n* add a better fix for nodes weird socket hang up error\n* add PUT/POST/PATCH data support to client short-hand functions\n* add .license property to component.json\n* change client portion to build using component(1)\n* fix GET body support [guille]\n\n# 0.9.7 / 2012-10-19\n\n* fix `.buffer()` `res.text` when no parser matches\n\n# 0.9.6 / 2012-10-17\n\n* change: use `this` when `window` is undefined\n* update to new component spec [juliangruber]\n* fix emission of \"data\" events for compressed responses without encoding. Closes [#125](https://github.com/ladjs/superagent/issues/125)\n\n# 0.9.5 / 2012-10-01\n\n* add field name to .attach()\n* add text \"parser\"\n* refactor isObject()\n* remove wtf isFunction() helper\n\n# 0.9.4 / 2012-09-20\n\n* fix `Buffer` responses [TooTallNate]\n* fix `res.type` when a \"type\" param is present [TooTallNate]\n\n# 0.9.3 / 2012-09-18\n\n* remove **GET** `.send()` == `.query()` special-case (**API** change !!!)\n\n# 0.9.2 / 2012-09-17\n\n* add `.aborted` prop\n* add `.abort()`. Closes [#115](https://github.com/ladjs/superagent/issues/115)\n\n# 0.9.1 / 2012-09-07\n\n* add `.forbidden` response property\n* add component.json\n* change emitter-component to 0.0.5\n* fix client-side tests\n\n# 0.9.0 / 2012-08-28\n\n* add `.timeout(ms)`. Closes [#17](https://github.com/ladjs/superagent/issues/17)\n\n# 0.8.2 / 2012-08-28\n\n* fix pathname relative redirects. Closes [#112](https://github.com/ladjs/superagent/issues/112)\n\n# 0.8.1 / 2012-08-21\n\n* fix redirects when schema is specified\n\n# 0.8.0 / 2012-08-19\n\n* add `res.buffered` flag\n* add buffering of text/\\*, json and forms only by default. Closes [#61](https://github.com/ladjs/superagent/issues/61)\n* add `.buffer(false)` cancellation\n* add cookie jar support [hunterloftis]\n* add agent functionality [hunterloftis]\n\n# 0.7.0 / 2012-08-03\n\n* allow `query()` to be called after the internal `req` has been created [tootallnate]\n\n# 0.6.0 / 2012-07-17\n\n* add `res.send('foo=bar')` default of \"application/x-www-form-urlencoded\"\n\n# 0.5.1 / 2012-07-16\n\n* add \"methods\" dep\n* add `.end()` arity check to node callbacks\n* fix unzip support due to weird node internals\n\n# 0.5.0 / 2012-06-16\n\n* Added \"Link\" response header field parsing, exposing `res.links`\n\n# 0.4.3 / 2012-06-15\n\n* Added 303, 305 and 307 as redirect status codes [slaskis]\n* Fixed passing an object as the url\n\n# 0.4.2 / 2012-06-02\n\n* Added component support\n* Fixed redirect data\n\n# 0.4.1 / 2012-04-13\n\n* Added HTTP PATCH support\n* Fixed: GET / HEAD when following redirects. Closes [#86](https://github.com/ladjs/superagent/issues/86)\n* Fixed Content-Length detection for multibyte chars\n\n# 0.4.0 / 2012-03-04\n\n* Added `.head()` method [browser]. Closes [#78](https://github.com/ladjs/superagent/issues/78)\n* Added `make test-cov` support\n* Added multipart request support. Closes [#11](https://github.com/ladjs/superagent/issues/11)\n* Added all methods that node supports. Closes [#71](https://github.com/ladjs/superagent/issues/71)\n* Added \"response\" event providing a Response object. Closes [#28](https://github.com/ladjs/superagent/issues/28)\n* Added `.query(obj)`. Closes [#59](https://github.com/ladjs/superagent/issues/59)\n* Added `res.type` (browser). Closes [#54](https://github.com/ladjs/superagent/issues/54)\n* Changed: default `res.body` and `res.files` to {}\n* Fixed: port existing query-string fix (browser). Closes [#57](https://github.com/ladjs/superagent/issues/57)\n\n# 0.3.0 / 2012-01-24\n\n* Added deflate/gzip support [guillermo]\n* Added `res.type` (Content-Type void of params)\n* Added `res.statusCode` to mirror node\n* Added `res.headers` to mirror node\n* Changed: parsers take callbacks\n* Fixed optional schema support. Closes [#49](https://github.com/ladjs/superagent/issues/49)\n\n# 0.2.0 / 2012-01-05\n\n* Added url auth support\n* Added `.auth(username, password)`\n* Added basic auth support [node]. Closes [#41](https://github.com/ladjs/superagent/issues/41)\n* Added `make test-docs`\n* Added guillermo's EventEmitter. Closes [#16](https://github.com/ladjs/superagent/issues/16)\n* Removed `Request#data()` for SS, renamed to `send()`\n* Removed `Request#data()` from client, renamed to `send()`\n* Fixed array support. [browser]\n* Fixed array support. Closes [#35](https://github.com/ladjs/superagent/issues/35) [node]\n* Fixed `EventEmitter#emit()`\n\n# 0.1.3 / 2011-10-25\n\n* Added error to callback\n* Bumped node dep for 0.5.x\n\n# 0.1.2 / 2011-09-24\n\n* Added markdown documentation\n* Added `request(url[, fn])` support to the client\n* Added `qs` dependency to package.json\n* Added options for `Request#pipe()`\n* Added support for `request(url, callback)`\n* Added `request(url)` as shortcut for `request.get(url)`\n* Added `Request#pipe(stream)`\n* Added inherit from `Stream`\n* Added multipart support\n* Added ssl support (node)\n* Removed Content-Length field from client\n* Fixed buffering, `setEncoding()` to utf8 [reported by stagas]\n* Fixed \"end\" event when piping\n\n# 0.1.1 / 2011-08-20\n\n* Added `res.redirect` flag (node)\n* Added redirect support (node)\n* Added `Request#redirects(n)` (node)\n* Added `.set(object)` header field support\n* Fixed `Content-Length` support\n\n# 0.1.0 / 2011-08-09\n\n* Added support for multiple calls to `.data()`\n* Added support for `.get(uri, obj)`\n* Added GET `.data()` querystring support\n* Added IE{6,7,8} support [alexyoung]\n\n# 0.0.1 / 2011-08-05\n\n* Initial commit\n\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "(The MIT License)\n\nCopyright (c) 2014-2016 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "OLDNODETESTS ?= lib/node/test/*.js lib/node/test/node/*.js\nNODETESTS ?= test/*.js test/node/*.js\nBROWSERTESTS ?= test/*.js test/client/*.js\nREPORTER = spec\n\nifeq (\"$(OLD_NODE_TEST)\", \"1\")\n\tNODETESTS := $(OLDNODETESTS)\nendif\n\ntest:\n\t@if [ \"$(BROWSER)\" = \"1\" ]; then \\\n\t\techo test on browser; \\\n\t\tmake test-browser; \\\n\tfi \\\n\n\t@if [ \"$(NODE_TEST)\" = \"1\" ] || [ \"x$(BROWSER)\" = \"x\" ]; then \\\n    echo test on node with http1; \\\n    export HTTP2_TEST=\"\" && make test-node; \\\n    if [ \"$(HTTP2_TEST_DISABLED)\" != \"1\" ]; then \\\n      echo test on node with http2; \\\n      export HTTP2_TEST=\"1\" && make test-node; \\\n    fi \\\n\tfi\n\ncopy:\n\t@if [ \"$(OLD_NODE_TEST)\" = \"1\" ]; then \\\n\t\techo test on old node; \\\n\t\tcp test/node/fixtures lib/node/test/node -rf; \\\n\telse \\\n\t\techo test on plain node; \\\n\tfi\n\ntest-node:copy\n\t@NODE_ENV=test HTTP2_TEST=$(HTTP2_TEST) ./node_modules/.bin/nyc ./node_modules/.bin/mocha \\\n\t\t--require should \\\n\t\t--trace-warnings \\\n\t\t--throw-deprecation \\\n\t\t--reporter $(REPORTER) \\\n\t\t--slow 2000 \\\n\t\t--timeout 5000 \\\n\t\t--exit \\\n\t\t$(NODETESTS)\n\ntest-cov: lib-cov\n\tSUPERAGENT_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html\n\ntest-browser:\n\tSAUCE_APPIUM_VERSION=1.7 ./node_modules/.bin/zuul -- $(BROWSERTESTS)\n\ntest-browser-local:\n\t./node_modules/.bin/zuul --no-coverage --local 4000 -- $(BROWSERTESTS)\n\nlib-cov:\n\tjscoverage lib lib-cov\n\ntest-server:\n\t@node test/server\n\ndocs: index.html test-docs docs/index.md\n\nindex.html: docs/index.md docs/head.html docs/tail.html\n\tmarked < $< \\\n\t\t| cat docs/head.html - docs/tail.html \\\n\t\t> $@\n\ndocclean:\n\trm -f index.html docs/test.html\n\ntest-docs: docs/head.html docs/tail.html\n\tmake test REPORTER=doc \\\n\t\t| cat docs/head.html - docs/tail.html \\\n\t\t> docs/test.html\n\nclean:\n\trm -fr components\n\n.PHONY: copy test-cov test docs test-docs clean test-browser-local\n"
  },
  {
    "path": "README.md",
    "content": "# superagent\n\n[![build status](https://github.com/forwardemail/superagent/actions/workflows/ci.yml/badge.svg)](https://github.com/forwardemail/superagent/actions/workflows/ci.yml)\n[![code coverage](https://img.shields.io/codecov/c/github/ladjs/superagent.svg)](https://codecov.io/gh/ladjs/superagent)\n[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)\n[![license](https://img.shields.io/github/license/ladjs/superagent.svg)](LICENSE)\n\n> Small progressive client-side HTTP request library, and Node.js module with the same API, supporting many high-level HTTP client features.  Maintained for [Forward Email](https://github.com/forwardemail) and [Lad](https://github.com/ladjs).\n\n\n## Table of Contents\n\n* [Install](#install)\n* [Usage](#usage)\n  * [Node](#node)\n  * [Browser](#browser)\n* [Supported Platforms](#supported-platforms)\n  * [Required Browser Features](#required-browser-features)\n* [Plugins](#plugins)\n* [Upgrading from previous versions](#upgrading-from-previous-versions)\n* [Contributors](#contributors)\n* [License](#license)\n\n\n## Install\n\n[npm][]:\n\n```sh\nnpm install superagent\n```\n\n[yarn][]:\n\n```sh\nyarn add superagent\n```\n\n\n## Usage\n\n### Node\n\n```js\nconst superagent = require('superagent');\n\n// callback\nsuperagent\n  .post('/api/pet')\n  .send({ name: 'Manny', species: 'cat' }) // sends a JSON post body\n  .set('X-API-Key', 'foobar')\n  .set('accept', 'json')\n  .end((err, res) => {\n    // Calling the end function will send the request\n  });\n\n// promise with then/catch\nsuperagent.post('/api/pet').then(console.log).catch(console.error);\n\n// promise with async/await\n(async () => {\n  try {\n    const res = await superagent.post('/api/pet');\n    console.log(res);\n  } catch (err) {\n    console.error(err);\n  }\n})();\n```\n\n### Browser\n\n**The browser-ready, minified version of `superagent` is only 50 KB (minified and gzipped).**\n\nBrowser-ready versions of this module are available via [jsdelivr][], [unpkg][], and also in the `node_modules/superagent/dist` folder in downloads of the `superagent` package.\n\n> Note that we also provide unminified versions with `.js` instead of `.min.js` file extensions.\n\n#### VanillaJS\n\nThis is the solution for you if you're just using `<script>` tags everywhere!\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/superagent\"></script>\n<!-- if you wish to use unpkg.com instead: -->\n<!-- <script src=\"https://unpkg.com/superagent\"></script> -->\n<script type=\"text/javascript\">\n  (function() {\n    // superagent is exposed as `window.superagent`\n    // if you wish to use \"request\" instead please\n    // uncomment the following line of code:\n    // `window.request = superagent;`\n    superagent\n      .post('/api/pet')\n      .send({ name: 'Manny', species: 'cat' }) // sends a JSON post body\n      .set('X-API-Key', 'foobar')\n      .set('accept', 'json')\n      .end(function (err, res) {\n        // Calling the end function will send the request\n      });\n  })();\n</script>\n```\n\n#### Bundler\n\nIf you are using [browserify][], [webpack][], [rollup][], or another bundler, then you can follow the same usage as [Node](#node) above.\n\n\n## Supported Platforms\n\n* Node: v14.18.0+\n* Browsers (see [.browserslistrc](.browserslistrc)):\n\n  ```sh\n  npx browserslist\n  ```\n\n  ```sh\n  and_chr 102\n  and_ff 101\n  and_qq 10.4\n  and_uc 12.12\n  android 101\n  chrome 103\n  chrome 102\n  chrome 101\n  chrome 100\n  edge 103\n  edge 102\n  edge 101\n  firefox 101\n  firefox 100\n  firefox 91\n  ios_saf 15.5\n  ios_saf 15.4\n  ios_saf 15.2-15.3\n  ios_saf 15.0-15.1\n  ios_saf 14.5-14.8\n  ios_saf 14.0-14.4\n  ios_saf 12.2-12.5\n  kaios 2.5\n  op_mini all\n  op_mob 64\n  opera 86\n  opera 85\n  safari 15.5\n  safari 15.4\n  samsung 17.0\n  samsung 16.0\n  ```\n\n### Required Browser Features\n\nWe recommend using <https://cdnjs.cloudflare.com/polyfill/> (specifically with the bundle mentioned in [VanillaJS](#vanillajs) above):\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt\"></script>\n```\n\n* WeakRef is not supported in Opera 85, iOS Safari 12.2-12.5\n* BigInt is not supported in iOS Safari 12.2-12.5\n\n\n## Plugins\n\nSuperAgent is easily extended via plugins.\n\n```js\nconst nocache = require('superagent-no-cache');\nconst superagent = require('superagent');\nconst prefix = require('superagent-prefix')('/static');\n\nsuperagent\n  .get('/some-url')\n  .query({ action: 'edit', city: 'London' }) // query string\n  .use(prefix) // Prefixes *only* this request\n  .use(nocache) // Prevents caching of *only* this request\n  .end((err, res) => {\n    // Do something\n  });\n```\n\nExisting plugins:\n\n* [superagent-no-cache](https://github.com/johntron/superagent-no-cache) - prevents caching by including Cache-Control header\n* [superagent-prefix](https://github.com/johntron/superagent-prefix) - prefixes absolute URLs (useful in test environment)\n* [superagent-suffix](https://github.com/timneutkens1/superagent-suffix) - suffix URLs with a given path\n* [superagent-mock](https://github.com/M6Web/superagent-mock) - simulate HTTP calls by returning data fixtures based on the requested URL\n* [superagent-mocker](https://github.com/shuvalov-anton/superagent-mocker) — simulate REST API\n* [superagent-cache](https://github.com/jpodwys/superagent-cache) - A global SuperAgent patch with built-in, flexible caching\n* [superagent-cache-plugin](https://github.com/jpodwys/superagent-cache-plugin) - A SuperAgent plugin with built-in, flexible caching\n* [superagent-jsonapify](https://github.com/alex94puchades/superagent-jsonapify) - A lightweight [json-api](http://jsonapi.org/format/) client addon for superagent\n* [superagent-serializer](https://github.com/zzarcon/superagent-serializer) - Converts server payload into different cases\n* [superagent-httpbackend](https://www.npmjs.com/package/superagent-httpbackend) - stub out requests using AngularJS' $httpBackend syntax\n* [superagent-throttle](https://github.com/leviwheatcroft/superagent-throttle) - queues and intelligently throttles requests\n* [superagent-charset](https://github.com/magicdawn/superagent-charset) - add charset support for node's SuperAgent\n* [superagent-verbose-errors](https://github.com/jcoreio/superagent-verbose-errors) - include response body in error messages for failed requests\n* [superagent-declare](https://github.com/damoclark/superagent-declare) - A simple [declarative](https://en.wikipedia.org/wiki/Declarative_programming) API for SuperAgent\n* [superagent-node-http-timings](https://github.com/webuniverseio/superagent-node-http-timings) - measure http timings in node.js\n* [superagent-cheerio](https://github.com/mmmmmrob/superagent-cheerio) - add [cheerio](https://www.npmjs.com/package/cheerio) to your response content automatically. Adds `res.$` for HTML and XML response bodies.\n* [@certible/superagent-aws-sign](https://github.com/certible/superagent-aws-sign) - Sign AWS endpoint requests, it uses the aws4 to authenticate the SuperAgent requests\n\nPlease prefix your plugin with `superagent-*` so that it can easily be found by others.\n\nFor SuperAgent extensions such as couchdb and oauth visit the [wiki](https://github.com/ladjs/superagent/wiki).\n\n\n## Upgrading from previous versions\n\nPlease see [GitHub releases page](https://github.com/ladjs/superagent/releases) for the current changelog.\n\nOur breaking changes are mostly in rarely used functionality and from stricter error handling.\n\n* [6.0 to 6.1](https://github.com/ladjs/superagent/releases/tag/v6.1.0)\n  * Browser behaviour changed to match Node when serializing `application/x-www-form-urlencoded`, using `arrayFormat: 'indices'` semantics of `qs` library. (See: <https://www.npmjs.com/package/qs#stringifying>)\n* [5.x to 6.x](https://github.com/ladjs/superagent/releases/tag/v6.0.0):\n  * Retry behavior is still opt-in, however we now have a more fine-grained list of status codes and error codes that we retry against (see updated docs)\n  * A specific issue with Content-Type matching not being case-insensitive is fixed\n  * Set is now required for IE 9, see [Required Browser Features](#required-browser-features) for more insight\n* [4.x to 5.x](https://github.com/ladjs/superagent/releases/tag/v5.0.0):\n  * We've implemented the build setup of [Lass](https://lass.js.org) to simplify our stack and linting\n  * Unminified browserified build size has been reduced from 48KB to 20KB (via `tinyify` and the latest version of Babel using `@babel/preset-env` and `.browserslistrc`)\n  * Linting support has been added using `caniuse-lite` and `eslint-plugin-compat`\n  * We can now target what versions of Node we wish to support more easily using `.babelrc`\n* [3.x to 4.x](https://github.com/ladjs/superagent/releases/tag/v4.0.0-alpha.1):\n  * Ensure you're running Node 6 or later. We've dropped support for Node 4.\n  * We've started using ES6 and for compatibility with Internet Explorer you may need to use Babel.\n  * We suggest migrating from `.end()` callbacks to `.then()` or `await`.\n* [2.x to 3.x](https://github.com/ladjs/superagent/releases/tag/v3.0.0):\n  * Ensure you're running Node 4 or later. We've dropped support for Node 0.x.\n  * Test code that calls `.send()` multiple times. Invalid calls to `.send()` will now throw instead of sending garbage.\n* [1.x to 2.x](https://github.com/ladjs/superagent/releases/tag/v2.0.0):\n  * If you use `.parse()` in the *browser* version, rename it to `.serialize()`.\n  * If you rely on `undefined` in query-string values being sent literally as the text \"undefined\", switch to checking for missing value instead. `?key=undefined` is now `?key` (without a value).\n  * If you use `.then()` in Internet Explorer, ensure that you have a polyfill that adds a global `Promise` object.\n* 0.x to 1.x:\n  * Instead of 1-argument callback `.end(function(res){})` use `.then(res => {})`.\n\n\n## Contributors\n\n| Name                |\n| ------------------- |\n| **Kornel Lesiński** |\n| **Peter Lyons**     |\n| **Hunter Loftis**   |\n| **Nick Baugh**      |\n\n\n## License\n\n[MIT](LICENSE) © TJ Holowaychuk\n\n\n##\n\n[npm]: https://www.npmjs.com/\n\n[yarn]: https://yarnpkg.com/\n\n[jsdelivr]: https://www.jsdelivr.com/\n\n[unpkg]: https://unpkg.com/\n\n[browserify]: https://github.com/browserify/browserify\n\n[webpack]: https://github.com/webpack/webpack\n\n[rollup]: https://github.com/rollup/rollup\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n\n## Reporting a Vulnerability\n\nPlease report security issues to `niftylettuce@gmail.com`\n"
  },
  {
    "path": "ci/remove-deps-4-old-node.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst package = require('../package.json');\n\nconst UNSUPPORT_DEPS_4_OLD = new Set([\n  '@commitlint/cli',\n  '@commitlint/config-conventional',\n  'eslint',\n  'eslint-config-xo-lass',\n  'eslint-plugin-compat',\n  'eslint-plugin-node',\n  'husky',\n  'lint-staged',\n  'marked',\n  'remark-cli',\n  'remark-preset-github',\n  'xo'\n]);\n\nfor (const item in package.devDependencies) {\n  if (UNSUPPORT_DEPS_4_OLD.has(item)) {\n    package.devDependencies[item] = undefined;\n  }\n}\n\nfs.writeFileSync(\n  path.join(__dirname, '../package.json'),\n  JSON.stringify(package, null, 2)\n);\n"
  },
  {
    "path": "docs/head.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css\">\n    <link rel=\"stylesheet\" href=\"docs/style.css\">\n  </head>\n  <body>\n    <ul id=\"menu\"></ul>\n    <div id=\"content\">\n"
  },
  {
    "path": "docs/index.md",
    "content": "\n# SuperAgent\n\nSuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!\n\n```javascript\n     request\n       .post('/api/pet')\n       .send({ name: 'Manny', species: 'cat' })\n       .set('X-API-Key', 'foobar')\n       .set('Accept', 'application/json')\n       .then(res => {\n          alert('yay got ' + JSON.stringify(res.body));\n       });\n```\n\n## Test documentation\n\n[**中文文档**](docs/zh_CN/index.html)\n\nThe following [test documentation](docs/test.html) was generated with [Mocha's](https://mochajs.org/) \"doc\" reporter, and directly reflects the test suite. This provides an additional source of documentation.\n\n## Request basics\n\nA request can be initiated by invoking the appropriate method on the `request` object, then calling `.then()` (or `.end()` [or `await`](#promise-and-generator-support)) to send the request. For example a simple __GET__ request:\n\n```javascript\n     request\n       .get('/search')\n       .then(res => {\n          // res.body, res.headers, res.status\n       })\n       .catch(err => {\n          // err.message, err.response\n       });\n```\n\nHTTP method may also be passed as a string:\n\n```javascript\n    request('GET', '/search').then(success, failure);\n```\n\nOld-style callbacks are also supported, but not recommended. *Instead of* `.then()` you can call `.end()`:\n\n```javascript\n    request('GET', '/search').end(function(err, res){\n      if (res.ok) {}\n    });\n```\n\nAbsolute URLs can be used. In web browsers absolute URLs work only if the server implements [CORS](#cors).\n\n```javascript\n     request\n       .get('https://example.com/search')\n       .then(res => {\n\n       });\n```\n\nThe __Node__ client supports making requests to [Unix Domain Sockets](https://en.wikipedia.org/wiki/Unix_domain_socket):\n\n```javascript\n    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n    //          Use `%2F` as `/` in SOCKET_PATH\n    try {\n      const res = await request\n        .get('http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search');\n      // res.body, res.headers, res.status\n    } catch(err) {\n      // err.message, err.response\n    }\n```\n\n__DELETE__, __HEAD__, __PATCH__, __POST__, and __PUT__ requests can also be used, simply change the method name:\n\n```javascript\n    request\n      .head('/favicon.ico')\n      .then(res => {\n\n      });\n```\n\n__DELETE__ can be also called as `.del()` for compatibility with old IE where `delete` is a reserved word.\n\nThe HTTP method defaults to __GET__, so if you wish, the following is valid:\n\n```javascript\n     request('/search', (err, res) => {\n\n     });\n```\n\n## Using HTTP/2\n\nTo make a request using HTTP/2 protocol only (with no HTTP/1.x fallback), use the `.http2()` method.\n\n```javascript\n    const request = require('superagent');\n    const res = await request\n      .get('https://example.com/h2')\n      .http2();\n```\n\n## Setting header fields\n\nSetting header fields is simple, invoke `.set()` with a field name and value:\n\n```javascript\n     request\n       .get('/search')\n       .set('API-Key', 'foobar')\n       .set('Accept', 'application/json')\n       .then(callback);\n```\n\nYou may also pass an object to set several fields in a single call:\n\n```javascript\n     request\n       .get('/search')\n       .set({ 'API-Key': 'foobar', Accept: 'application/json' })\n       .then(callback);\n```\n\n## `GET` requests\n\nThe `.query()` method accepts objects, which when used with the __GET__ method will form a query-string. The following will produce the path `/search?query=Manny&range=1..5&order=desc`.\n\n```javascript\n     request\n       .get('/search')\n       .query({ query: 'Manny' })\n       .query({ range: '1..5' })\n       .query({ order: 'desc' })\n       .then(res => {\n\n       });\n```\n\nOr as a single object:\n\n```javascript\n    request\n      .get('/search')\n      .query({ query: 'Manny', range: '1..5', order: 'desc' })\n      .then(res => {\n\n      });\n```\n\nThe `.query()` method accepts strings as well:\n\n```javascript\n      request\n        .get('/querystring')\n        .query('search=Manny&range=1..5')\n        .then(res => {\n\n        });\n```\n\nOr joined:\n\n```javascript\n      request\n        .get('/querystring')\n        .query('search=Manny')\n        .query('range=1..5')\n        .then(res => {\n\n        });\n```\n\n## `HEAD` requests\n\nYou can also use the `.query()` method for HEAD requests. The following will produce the path `/users?email=joe@smith.com`.\n\n```javascript\n      request\n        .head('/users')\n        .query({ email: 'joe@smith.com' })\n        .then(res => {\n\n        });\n```\n\n## `POST` / `PUT` requests\n\nA typical JSON __POST__ request might look a little like the following, where we set the Content-Type header field appropriately, and \"write\" some data, in this case just a JSON string.\n\n```javascript\n      request.post('/user')\n        .set('Content-Type', 'application/json')\n        .send('{\"name\":\"tj\",\"pet\":\"tobi\"}')\n        .then(callback)\n        .catch(errorCallback)\n```\n\nSince JSON is undoubtedly the most common, it's the _default_! The following example is equivalent to the previous.\n\n```javascript\n      request.post('/user')\n        .send({ name: 'tj', pet: 'tobi' })\n        .then(callback, errorCallback)\n```\n\nOr using multiple `.send()` calls:\n\n```javascript\n      request.post('/user')\n        .send({ name: 'tj' })\n        .send({ pet: 'tobi' })\n        .then(callback, errorCallback)\n```\n\nBy default sending strings will set the `Content-Type` to `application/x-www-form-urlencoded`,\n  multiple calls will be concatenated with `&`, here resulting in `name=tj&pet=tobi`:\n\n```javascript\n      request.post('/user')\n        .send('name=tj')\n        .send('pet=tobi')\n        .then(callback, errorCallback);\n```\n\nSuperAgent formats are extensible, however by default \"json\" and \"form\" are supported. To send the data as `application/x-www-form-urlencoded` simply invoke `.type()` with \"form\", where the default is \"json\". This request will __POST__ the body \"name=tj&pet=tobi\".\n\n```javascript\n      request.post('/user')\n        .type('form')\n        .send({ name: 'tj' })\n        .send({ pet: 'tobi' })\n        .then(callback, errorCallback)\n```\n\nSending a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData) object is also supported. The following example will __POST__ the content of the HTML form identified by id=\"myForm\":\n\n```javascript\n      request.post('/user')\n        .send(new FormData(document.getElementById('myForm')))\n        .then(callback, errorCallback)\n```\n\n## Setting the `Content-Type`\n\nThe obvious solution is to use the `.set()` method:\n\n```javascript\n     request.post('/user')\n       .set('Content-Type', 'application/json')\n```\n\nAs a short-hand the `.type()` method is also available, accepting\nthe canonicalized MIME type name complete with type/subtype, or\nsimply the extension name such as \"xml\", \"json\", \"png\", etc:\n\n```javascript\n     request.post('/user')\n       .type('application/json')\n\n     request.post('/user')\n       .type('json')\n\n     request.post('/user')\n       .type('png')\n```\n\n## Serializing request body\n\nSuperAgent will automatically serialize JSON and forms.\nYou can setup automatic serialization for other types as well:\n\n```js\nrequest.serialize['application/xml'] = function (obj) {\n    return 'string generated from obj';\n};\n\n// going forward, all requests with a Content-type of\n// 'application/xml' will be automatically serialized\n```\nIf you want to send the payload in a custom format, you can replace\nthe built-in serialization with the `.serialize()` method on a per-request basis:\n\n```js\nrequest\n    .post('/user')\n    .send({foo: 'bar'})\n    .serialize(obj => {\n        return 'string generated from obj';\n    });\n```\n## Retrying requests\n\nWhen given the `.retry()` method, SuperAgent will automatically retry requests, if they fail in a way that is transient or could be due to a flaky Internet connection.\n\nThis method has two optional arguments: number of retries (default 1) and a callback. It calls `callback(err, res)` before each retry. The callback may return `true`/`false` to control whether the request should be retried (but the maximum number of retries is always applied).\n\n```javascript\n     request\n       .get('https://example.com/search')\n       .retry(2) // or:\n       .retry(2, callback)\n       .then(finished);\n       .catch(failed);\n```\n\nUse `.retry()` only with requests that are *idempotent* (i.e. multiple requests reaching the server won't cause undesirable side effects like duplicate purchases).\n\nAll request methods are tried by default (which means if you do not want POST requests to be retried, you will need to pass a custom retry callback).\n\nBy default the following status codes are retried:\n\n* `408`\n* `413`\n* `429`\n* `500`\n* `502`\n* `503`\n* `504`\n* `521`\n* `522`\n* `524`\n\nBy default the following error codes are retried:\n\n* `'ETIMEDOUT'`\n* `'ECONNRESET'`\n* `'EADDRINUSE'`\n* `'ECONNREFUSED'`\n* `'EPIPE'`\n* `'ENOTFOUND'`\n* `'ENETUNREACH'`\n* `'EAI_AGAIN'`\n\n## Setting Accept\n\nIn a similar fashion to the `.type()` method it is also possible to set the `Accept` header via the short hand method `.accept()`. Which references `request.types` as well allowing you to specify either the full canonicalized MIME type name as `type/subtype`, or the extension suffix form as \"xml\", \"json\", \"png\", etc. for convenience:\n\n```javascript\n     request.get('/user')\n       .accept('application/json')\n\n     request.get('/user')\n       .accept('json')\n\n     request.post('/user')\n       .accept('png')\n```\n\n### Facebook and Accept JSON\n\nIf you are calling Facebook's API, be sure to send an `Accept: application/json` header in your request. If you don't do this, Facebook will respond with `Content-Type: text/javascript; charset=UTF-8`, which SuperAgent will not parse and thus `res.body` will be undefined. You can do this with either `req.accept('json')` or `req.set('Accept', 'application/json')`. See [issue 1078](https://github.com/ladjs/superagent/issues/1078) for details.\n\n## Query strings\n\n  `req.query(obj)` is a method which may be used to build up a query-string. For example populating `?format=json&dest=/login` on a __POST__:\n\n```javascript\n    request\n      .post('/')\n      .query({ format: 'json' })\n      .query({ dest: '/login' })\n      .send({ post: 'data', here: 'wahoo' })\n      .then(callback);\n```\n\nBy default the query string is not assembled in any particular order. An asciibetically-sorted query string can be enabled with `req.sortQuery()`. You may also provide a custom sorting comparison function with `req.sortQuery(myComparisonFn)`. The comparison function should take 2 arguments and return a negative/zero/positive integer.\n\n```js\n // default order\n request.get('/user')\n   .query('name=Nick')\n   .query('search=Manny')\n   .sortQuery()\n   .then(callback)\n\n // customized sort function\n request.get('/user')\n   .query('name=Nick')\n   .query('search=Manny')\n   .sortQuery((a, b) => a.length - b.length)\n   .then(callback)\n```\n\n## TLS options\n\nIn Node.js SuperAgent supports methods to configure HTTPS requests:\n\n- `.ca()`: Set the CA certificate(s) to trust\n- `.cert()`: Set the client certificate chain(s)\n- `.key()`: Set the client private key(s)\n- `.pfx()`: Set the client PFX or PKCS12 encoded private key and certificate chain\n- `.disableTLSCerts()`: Does not reject expired or invalid TLS certs. Sets internally `rejectUnauthorized=true`. *Be warned, this method allows MITM attacks.*\n\nFor more information, see Node.js [https.request docs](https://nodejs.org/api/https.html#https_https_request_options_callback).\n\n```js\nvar key = fs.readFileSync('key.pem'),\n    cert = fs.readFileSync('cert.pem');\n\nrequest\n  .post('/client-auth')\n  .key(key)\n  .cert(cert)\n  .then(callback);\n```\n\n```js\nvar ca = fs.readFileSync('ca.cert.pem');\n\nrequest\n  .post('https://localhost/private-ca-server')\n  .ca(ca)\n  .then(res => {});\n```\n\n## Parsing response bodies\n\nSuperAgent will parse known response-body data for you,\ncurrently supporting `application/x-www-form-urlencoded`,\n`application/json`, and `multipart/form-data`. You can setup\nautomatic parsing for other response-body data as well:\n\n```js\n//browser\nrequest.parse['application/xml'] = function (str) {\n    return {'object': 'parsed from str'};\n};\n\n//node\nrequest.parse['application/xml'] = function (res, cb) {\n    //parse response text and set res.body here\n\n    cb(null, res);\n};\n\n//going forward, responses of type 'application/xml'\n//will be parsed automatically\n```\n\nYou can set a custom parser (that takes precedence over built-in parsers) with the `.buffer(true).parse(fn)` method. If response buffering is not enabled (`.buffer(false)`) then the `response` event will be emitted without waiting for the body parser to finish, so `response.body` won't be available.\n\n### JSON / Urlencoded\n\nThe property `res.body` is the parsed object, for example if a request responded with the JSON string '{\"user\":{\"name\":\"tobi\"}}', `res.body.user.name` would be \"tobi\". Likewise the x-www-form-urlencoded value of \"user[name]=tobi\" would yield the same result. Only one level of nesting is supported. If you need more complex data, send JSON instead.\n\nArrays are sent by repeating the key. `.send({color: ['red','blue']})` sends `color=red&color=blue`. If you want the array keys to contain `[]` in their name, you must add it yourself, as SuperAgent doesn't add it automatically.\n\n### Multipart\n\nThe Node client supports _multipart/form-data_ via the [Formidable](https://github.com/felixge/node-formidable) module. When parsing multipart responses, the object `res.files` is also available to you. Suppose for example a request responds with the following multipart body:\n\n    --whoop\n    Content-Disposition: attachment; name=\"image\"; filename=\"tobi.png\"\n    Content-Type: image/png\n\n    ... data here ...\n    --whoop\n    Content-Disposition: form-data; name=\"name\"\n    Content-Type: text/plain\n\n    Tobi\n    --whoop--\n\nYou would have the values `res.body.name` provided as \"Tobi\", and `res.files.image` as a `File` object containing the path on disk, filename, and other properties.\n\n### Binary\n\nIn browsers, you may use `.responseType('blob')` to request handling of binary response bodies. This API is unnecessary when running in node.js. The supported argument values for this method are\n\n- `'blob'` passed through to the XmlHTTPRequest `responseType` property\n- `'arraybuffer'` passed through to the XmlHTTPRequest `responseType` property\n\n```js\nreq.get('/binary.data')\n  .responseType('blob')\n  .then(res => {\n    // res.body will be a browser native Blob type here\n  });\n```\n\nFor more information, see the Mozilla Developer Network [xhr.responseType docs](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).\n\n## Response properties\n\nMany helpful flags and properties are set on the `Response` object, ranging from the response text, parsed response body, header fields, status flags and more.\n\n### Response text\n\nThe `res.text` property contains the unparsed response body string. This property is always present for the client API, and only when the mime type matches \"text/*\", \"*/json\", or \"x-www-form-urlencoded\" by default for node. The reasoning is to conserve memory, as buffering text of large bodies such as multipart files or images is extremely inefficient. To force buffering see the \"Buffering responses\" section.\n\n### Response body\n\nMuch like SuperAgent can auto-serialize request data, it can also automatically parse it. When a parser is defined for the Content-Type, it is parsed, which by default includes \"application/json\" and \"application/x-www-form-urlencoded\". The parsed object is then available via `res.body`.\n\n### Response header fields\n\nThe `res.header` contains an object of parsed header fields, lowercasing field names much like node does. For example `res.header['content-length']`.\n\n### Response Content-Type\n\nThe Content-Type response header is special-cased, providing `res.type`, which is void of the charset (if any). For example the Content-Type of \"text/html; charset=utf8\" will provide \"text/html\" as `res.type`, and the `res.charset` property would then contain \"utf8\".\n\n### Response status\n\nThe response status flags help determine if the request was a success, among other useful information, making SuperAgent ideal for interacting with RESTful web services. These flags are currently defined as:\n\n```javascript\n     var type = status / 100 | 0;\n\n     // status / class\n     res.status = status;\n     res.statusType = type;\n\n     // basics\n     res.info = 1 == type;\n     res.ok = 2 == type;\n     res.clientError = 4 == type;\n     res.serverError = 5 == type;\n     res.error = 4 == type || 5 == type;\n\n     // sugar\n     res.accepted = 202 == status;\n     res.noContent = 204 == status || 1223 == status;\n     res.badRequest = 400 == status;\n     res.unauthorized = 401 == status;\n     res.notAcceptable = 406 == status;\n     res.notFound = 404 == status;\n     res.forbidden = 403 == status;\n```\n\n## Aborting requests\n\nTo abort requests simply invoke the `req.abort()` method.\n\n## Timeouts\n\nSometimes networks and servers get \"stuck\" and never respond after accepting a request. Set timeouts to avoid requests waiting forever.\n\n  * `req.timeout({deadline:ms})` or `req.timeout(ms)` (where `ms` is a number of milliseconds > 0) sets a deadline for the entire request (including all uploads, redirects, server processing time) to complete. If the response isn't fully downloaded within that time, the request will be aborted.\n\n  * `req.timeout({response:ms})` sets maximum time to wait for the first byte to arrive from the server, but it does not limit how long the entire download can take. Response timeout should be at least few seconds longer than just the time it takes the server to respond, because it also includes time to make DNS lookup, TCP/IP and TLS connections, and time to upload request data.\n\nYou should use both `deadline` and `response` timeouts. This way you can use a short response timeout to detect unresponsive networks quickly, and a long deadline to give time for downloads on slow, but reliable, networks. Note that both of these timers limit how long *uploads* of attached files are allowed to take. Use long timeouts if you're uploading files.\n\n```javascript\n    request\n      .get('/big-file?network=slow')\n      .timeout({\n        response: 5000,  // Wait 5 seconds for the server to start sending,\n        deadline: 60000, // but allow 1 minute for the file to finish loading.\n      })\n      .then(res => {\n          /* responded in time */\n        }, err => {\n          if (err.timeout) { /* timed out! */ } else { /* other error */ }\n      });\n```\n\nTimeout errors have a `.timeout` property.\n\n## Authentication\n\nIn both Node and browsers auth available via the `.auth()` method:\n\n```javascript\n    request\n      .get('http://local')\n      .auth('tobi', 'learnboost')\n      .then(callback);\n```\n\nIn the _Node_ client Basic auth can be in the URL as \"user:pass\":\n\n```javascript\n    request.get('http://tobi:learnboost@local').then(callback);\n```\n\nBy default only `Basic` auth is used. In browser you can add `{type:'auto'}` to enable all methods built-in in the browser (Digest, NTLM, etc.):\n\n```javascript\n    request.auth('digest', 'secret', {type:'auto'})\n```\n\nThe `auth` method also supports a `type` of `bearer`, to specify token-based authentication:\n\n```javascript\n    request.auth('my_token', { type: 'bearer' })\n```\n\n## Following redirects\n\nBy default up to 5 redirects will be followed, however you may specify this with the `res.redirects(n)` method:\n\n```javascript\n    const response = await request.get('/some.png').redirects(2);\n```\n\nRedirects exceeding the limit are treated as errors. Use `.ok(res => res.status < 400)` to read them as successful responses.\n\n## Agents for global state\n\n### Saving cookies\n\nIn Node SuperAgent does not save cookies by default, but you can use the `.agent()` method to create a copy of SuperAgent that saves cookies. Each copy has a separate cookie jar.\n\n```javascript\n    const agent = request.agent();\n    agent\n      .post('/login')\n      .then(() => {\n        return agent.get('/cookied-page');\n      });\n```\n\nIn browsers cookies are managed automatically by the browser, so the `.agent()` does not isolate cookies.\n\n### Default options for multiple requests\n\nRegular request methods called on the agent will be used as defaults for all requests made by that agent.\n\n```javascript\n    const agent = request.agent()\n      .use(plugin)\n      .auth(shared);\n\n    await agent.get('/with-plugin-and-auth');\n    await agent.get('/also-with-plugin-and-auth');\n```\n\nThe complete list of methods that the agent can use to set defaults is: `use`, `on`, `once`, `set`, `query`, `type`, `accept`, `auth`, `withCredentials`, `sortQuery`, `retry`, `ok`, `redirects`, `timeout`, `buffer`, `serialize`, `parse`, `ca`, `key`, `pfx`, `cert`.\n\n## Piping data\n\nThe Node client allows you to pipe data to and from the request. Please note that `.pipe()` is used **instead of** `.end()`/`.then()` methods.\n\nFor example piping a file's contents as the request:\n\n```javascript\n    const request = require('superagent');\n    const fs = require('fs');\n\n    const stream = fs.createReadStream('path/to/my.json');\n    const req = request.post('/somewhere');\n    req.type('json');\n    stream.pipe(req);\n```\n\nNote that when you pipe to a request, superagent sends the piped data with [chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding), which isn't supported by all servers (for instance, Python WSGI servers).\n\nOr piping the response to a file:\n\n```javascript\n    const stream = fs.createWriteStream('path/to/my.json');\n    const req = request.get('/some.json');\n    req.pipe(stream);\n```\n\n It's not possible to mix pipes and callbacks or promises. Note that you should **NOT** attempt to pipe the result of `.end()` or the `Response` object:\n\n```javascript\n    // Don't do either of these:\n    const stream = getAWritableStream();\n    const req = request\n      .get('/some.json')\n      // BAD: this pipes garbage to the stream and fails in unexpected ways\n      .end((err, this_does_not_work) => this_does_not_work.pipe(stream))\n    const req = request\n      .get('/some.json')\n      .end()\n      // BAD: this is also unsupported, .pipe calls .end for you.\n      .pipe(nope_its_too_late);\n```\n\nIn a [future version](https://github.com/ladjs/superagent/issues/1188) of superagent, improper calls to `pipe()` will fail.\n\n## Multipart requests\n\nSuperAgent is also great for _building_ multipart requests for which it provides methods `.attach()` and `.field()`.\n\nWhen you use `.field()` or `.attach()` you can't use `.send()` and you *must not* set `Content-Type` (the correct type will be set for you).\n\n### Attaching files\n\nTo send a file use `.attach(name, [file], [options])`. You can attach multiple files by calling `.attach` multiple times. The arguments are:\n\n * `name` — field name in the form.\n * `file` — either string with file path or `Blob`/`Buffer` object.\n * `options` — (optional) either string with custom file name or `{filename: string}` object. In Node also `{contentType: 'mime/type'}` is supported. In browser create a `Blob` with an appropriate type instead.\n\n<br>\n\n```javascript\n    request\n      .post('/upload')\n      .attach('image1', 'path/to/felix.jpeg')\n      .attach('image2', imageBuffer, 'luna.jpeg')\n      .field('caption', 'My cats')\n      .then(callback);\n```\n\n### Field values\n\nMuch like form fields in HTML, you can set field values with `.field(name, value)` and `.field({name: value})`. Suppose you want to upload a few images with your name and email, your request might look something like this:\n\n```javascript\n     request\n       .post('/upload')\n       .field('user[name]', 'Tobi')\n       .field('user[email]', 'tobi@learnboost.com')\n       .field('friends[]', ['loki', 'jane'])\n       .attach('image', 'path/to/tobi.png')\n       .then(callback);\n```\n\n## Compression\n\nThe node client supports compressed responses, best of all, you don't have to do anything! It just works.\n\n## Buffering responses\n\nTo force buffering of response bodies as `res.text` you may invoke `req.buffer()`. To undo the default of buffering for text responses such as \"text/plain\", \"text/html\" etc you may invoke `req.buffer(false)`.\n\nWhen buffered the `res.buffered` flag is provided, you may use this to handle both buffered and unbuffered responses in the same callback.\n\n## CORS\n\nFor security reasons, browsers will block cross-origin requests unless the server opts-in using CORS headers. Browsers will also make extra __OPTIONS__ requests to check what HTTP headers and methods are allowed by the server. [Read more about CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS).\n\nThe `.withCredentials()` method enables the ability to send cookies from the origin, however only when `Access-Control-Allow-Origin` is _not_ a wildcard (\"*\"), and `Access-Control-Allow-Credentials` is \"true\".\n\n```javascript\n    request\n      .get('https://api.example.com:4001/')\n      .withCredentials()\n      .then(res => {\n        assert.equal(200, res.status);\n        assert.equal('tobi', res.text);\n      })\n```\n\n## Error handling\n\nYour callback function will always be passed two arguments: error and response. If no error occurred, the first argument will be null:\n\n```javascript\n    request\n     .post('/upload')\n     .attach('image', 'path/to/tobi.png')\n     .then(res => {\n\n     });\n```\n\nAn \"error\" event is also emitted, with you can listen for:\n\n```javascript\n    request\n      .post('/upload')\n      .attach('image', 'path/to/tobi.png')\n      .on('error', handle)\n      .then(res => {\n\n      });\n```\n\nNote that **superagent considers 4xx and 5xx responses (as well as unhandled 3xx responses) errors by default**. For example, if you get a `304 Not modified`, `403 Forbidden` or `500 Internal server error` response, this status information will be available via `err.status`. Errors from such responses also contain an `err.response` field with all of the properties mentioned in \"[Response properties](#response-properties)\". The library behaves in this way to handle the common case of wanting success responses and treating HTTP error status codes as errors while still allowing for custom logic around specific error conditions.\n\nNetwork failures, timeouts, and other errors that produce no response will contain no `err.status` or `err.response` fields.\n\nIf you wish to handle 404 or other HTTP error responses, you can query the `err.status` property. When an HTTP error occurs (4xx or 5xx response) the `res.error` property is an `Error` object, this allows you to perform checks such as:\n\n```javascript\n    if (err && err.status === 404) {\n      alert('oh no ' + res.body.message);\n    }\n    else if (err) {\n      // all other error types we handle generically\n    }\n```\n\nAlternatively, you can use the `.ok(callback)` method to decide whether a response is an error or not. The callback to the `ok` function gets a response and returns `true` if the response should be interpreted as success.\n\n```javascript\n    request.get('/404')\n      .ok(res => res.status < 500)\n      .then(response => {\n        // reads 404 page as a successful response\n      })\n```\n\n## Progress tracking\n\nSuperAgent fires `progress` events on upload and download of large files.\n\n```javascript\n    request.post(url)\n      .attach('field_name', file)\n      .on('progress', event => {\n        /* the event is:\n        {\n          direction: \"upload\" or \"download\"\n          percent: 0 to 100 // may be missing if file size is unknown\n          total: // total file size, may be missing\n          loaded: // bytes downloaded or uploaded so far\n        } */\n      })\n      .then()\n```\n\n## Testing on localhost\n\n### Forcing specific connection IP address\n\nIn Node.js it's possible to ignore DNS resolution and direct all requests to a specific IP address using `.connect()` method. For example, this request will go to localhost instead of `example.com`:\n\n```javascript\n    const res = await request.get(\"http://example.com\").connect(\"127.0.0.1\");\n```\n\nBecause the request may be redirected, it's possible to specify multiple hostnames and multiple IPs, as well as a special `*` as the fallback (note: other wildcards are not supported). The requests will keep their `Host` header with the original value. `.connect(undefined)` turns off the feature.\n\n```javascript\n    const res = await request.get(\"http://redir.example.com:555\")\n      .connect({\n        \"redir.example.com\": \"127.0.0.1\", // redir.example.com:555 will use 127.0.0.1:555\n        \"www.example.com\": false, // don't override this one; use DNS as normal\n        \"mapped.example.com\": { host: \"127.0.0.1\", port: 8080}, // mapped.example.com:* will use 127.0.0.1:8080\n        \"*\": \"proxy.example.com\", // all other requests will go to this host\n      });\n```\n\n### Ignoring broken/insecure HTTPS on localhost\n\nIn Node.js, when HTTPS is misconfigured and insecure (e.g. using self-signed certificate *without* specifying own `.ca()`), it's still possible to permit requests to `localhost` by calling `.trustLocalhost()`:\n\n```javascript\n    const res = await request.get(\"https://localhost\").trustLocalhost()\n```\n\nTogether with `.connect(\"127.0.0.1\")` this may be used to force HTTPS requests to any domain to be re-routed to `localhost` instead.\n\nIt's generally safe to ignore broken HTTPS on `localhost`, because the loopback interface is not exposed to untrusted networks. Trusting `localhost` may become the default in the future. Use `.trustLocalhost(false)` to force check of `127.0.0.1`'s authenticity.\n\nWe intentionally don't support disabling of HTTPS security when making requests to any other IP, because such options end up abused as a quick \"fix\" for HTTPS problems. You can get free HTTPS certificates from [Let's Encrypt](https://certbot.eff.org) or set your own CA (`.ca(ca_public_pem)`) to make your self-signed certificates trusted.\n\n## Promise and Generator support\n\nSuperAgent's request is a \"thenable\" object that's compatible with JavaScript promises and the `async`/`await` syntax.\n\n```javascript\n    const res = await request.get(url);\n```\n\nIf you're using promises, **do not** call `.end()` or `.pipe()`. Any use of `.then()` or `await` disables all other ways of using the request.\n\nLibraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any SuperAgent method:\n\n```javascript\n    const req = request\n      .get('http://local')\n      .auth('tobi', 'learnboost');\n    const res = yield req;\n```\n\nNote that SuperAgent expects the global `Promise` object to be present. You'll need to use v7 and a polyfill to use promises in Internet Explorer or Node.js 0.10.\n\nWe have dropped support in v8 for IE.  You must add a polyfill for WeakRef and BigInt if you wish to support Opera 85, iOS Safari 12.2-12.5, for example using <https://cdnjs.cloudflare.com/polyfill/>:\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt\"></script>\n```\n\n## Browser and node versions\n\nSuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.\n\nIf want to use WebPack to compile code for Node.JS, you *must* specify [node target](https://webpack.github.io/docs/configuration.html#target) in its configuration.\n"
  },
  {
    "path": "docs/ko_KR/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\" />\n    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css\"\n    />\n    <link rel=\"stylesheet\" href=\"../style.css\" />\n  </head>\n  <body>\n    <ul id=\"menu\"></ul>\n    <div id=\"content\">\n      <h1 id=\"superagent\">SuperAgent</h1>\n      <p>\n        SuperAgent는 기존의 복잡한 요청 API에 대한 불만에서 출발해 유연성,\n        가독성, 그리고 낮은 학습 난이도를 목표로 설계된 경량 Ajax API입니다.\n        또한 Node.js 환경에서도 동작합니다!\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .post(&#39;/api/pet&#39;)\n       .send({ name: &#39;Manny&#39;, species: &#39;cat&#39; })\n       .set(&#39;X-API-Key&#39;, &#39;foobar&#39;)\n       .set(&#39;Accept&#39;, &#39;application/json&#39;)\n       .then(res =&gt; {\n          alert(&#39;yay got &#39; + JSON.stringify(res.body));\n       });\n</code></pre>\n      <h2 id=\"test-documentation\">테스트 문서</h2>\n      <p>\n        <a href=\"../../index.html\"><strong>English</strong></a>\n      </p>\n      <p>\n        다음의 <a href=\"../test.html\">테스트 문서</a>는\n        <a href=\"https://mochajs.org/\">Mocha&#39;s</a> &quot;doc&quot; 리포터를\n        사용해 생성되었으며, 실제 테스트 스위트를 직접 반영합니다. 이 문서는\n        추가적인 참고 자료로 활용할 수 있습니다.\n      </p>\n      <h2 id=\"request-basics\">기본 요청</h2>\n      <p>\n        요청은 <code>request</code> 객체에서 적절한 메서드를 호출하여 시작되며,\n        그 다음 <code>.then()</code> 또는 <code>.end()</code> 혹은\n        <a href=\"#promise-and-generator-support\"><code>await</code></a\n        >를 사용해 요청을 전송할 수 있습니다. 예를 들어, 간단한\n        <strong>GET</strong> 요청은 다음과 같습니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .then(res =&gt; {\n          // res.body, res.headers, res.status\n       })\n       .catch(err =&gt; {\n          // err.message, err.response\n       });\n</code></pre>\n      <p>HTTP 메서드는 문자열로도 전달할 수 있습니다.</p>\n      <pre><code class=\"language-javascript\">    request(&#39;GET&#39;, &#39;/search&#39;).then(success, failure);\n</code></pre>\n      <p>\n        예전 방식의 콜백도 지원되지만, 권장되지는 않습니다.\n        <code>.then()</code> 대신 <code>.end()</code>를 호출하여 요청을 전송할\n        수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request(&#39;GET&#39;, &#39;/search&#39;).end(function(err, res){\n      if (res.ok) {}\n    });\n</code></pre>\n      <p>\n        절대 URL을 사용할 수 있습니다. 단, 웹 브라우저에서는 서버가\n        <a href=\"#cors\">CORS</a>를 구현한 경우에만 절대 URL이 정상적으로\n        작동합니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;https://example.com/search&#39;)\n       .then(res =&gt; {\n\n       });\n</code></pre>\n      <p>\n        <strong>Node</strong> 클라이언트는\n        <a\n          href=\"https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%89%EC%8A%A4_%EB%8F%84%EB%A9%94%EC%9D%B8_%EC%86%8C%EC%BC%93\"\n          >유닉스 도메인 소켓</a\n        >을 통한 요청을 지원합니다.\n      </p>\n      <pre><code class=\"language-javascript\">    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n    //          Use `%2F` as `/` in SOCKET_PATH\n    try {\n      const res = await request\n        .get(&#39;http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search&#39;);\n      // res.body, res.headers, res.status\n    } catch(err) {\n      // err.message, err.response\n    }\n</code></pre>\n      <p>\n        <strong>DELETE</strong>, <strong>HEAD</strong>, <strong>PATCH</strong>,\n        <strong>POST</strong>, and <strong>PUT</strong> 요청도 사용할 수 있으며,\n        다음 예시에서 메서드 이름만 변경하면 됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .head(&#39;/favicon.ico&#39;)\n      .then(res =&gt; {\n\n      });\n</code></pre>\n      <p>\n        <strong>DELETE</strong>는 <code>delete</code>가 예약어였던 구형 IE와의\n        호환성을 위해 <code>.del()</code> 메서드로도 호출할 수 있습니다.\n      </p>\n      <p>\n        HTTP 메서드의 기본값은 <strong>GET</strong>이므로, 다음과 같이 작성해도\n        유효합니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request(&#39;/search&#39;, (err, res) =&gt; {\n\n     });\n</code></pre>\n      <h2 id=\"using-http/2\">HTTP/2 사용하기</h2>\n      <p>\n        HTTP/1.x 폴백 없이 HTTP/2 프로토콜만 사용하려면\n        <code>.http2()</code> 메서드를 호출하여 요청을 전송할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const request = require(&#39;superagent&#39;);\n    const res = await request\n      .get(&#39;https://example.com/h2&#39;)\n      .http2();\n</code></pre>\n      <h2 id=\"setting-header-fields\">헤더 필드 설정하기</h2>\n      <p>\n        헤더 필드 설정은 간단합니다. 필드 이름과 값을\n        <code>.set()</code> 메서드에 전달하면 됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .set(&#39;API-Key&#39;, &#39;foobar&#39;)\n       .set(&#39;Accept&#39;, &#39;application/json&#39;)\n       .then(callback);\n</code></pre>\n      <p>여러 개의 헤더 필드를 한 번에 설정하려면 객체를 전달하면 됩니다.</p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .set({ &#39;API-Key&#39;: &#39;foobar&#39;, Accept: &#39;application/json&#39; })\n       .then(callback);\n</code></pre>\n      <h2 id=\"get-requests\"><code>GET</code> 요청</h2>\n      <p>\n        <code>.query()</code> 메서드는 객체를 인자로 받아\n        <strong>GET</strong> 요청 시 쿼리 문자열을 자동으로 생성합니다. 예를\n        들어 다음 코드는\n        <code>/search?query=Manny&amp;range=1..5&amp;order=desc</code> 경로를\n        생성합니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .query({ query: &#39;Manny&#39; })\n       .query({ range: &#39;1..5&#39; })\n       .query({ order: &#39;desc&#39; })\n       .then(res =&gt; {\n\n       });\n</code></pre>\n      <p>또는 하나의 객체로 설정할 수 있습니다.</p>\n      <pre><code class=\"language-javascript\">    request\n      .get(&#39;/search&#39;)\n      .query({ query: &#39;Manny&#39;, range: &#39;1..5&#39;, order: &#39;desc&#39; })\n      .then(res =&gt; {\n\n      });\n</code></pre>\n      <p><code>.query()</code> 메서드는 문자열도 받습니다.</p>\n      <pre><code class=\"language-javascript\">      request\n        .get(&#39;/querystring&#39;)\n        .query(&#39;search=Manny&amp;range=1..5&#39;)\n        .then(res =&gt; {\n\n        });\n</code></pre>\n      <p>조인할 수도 있습니다.</p>\n      <pre><code class=\"language-javascript\">      request\n        .get(&#39;/querystring&#39;)\n        .query(&#39;search=Manny&#39;)\n        .query(&#39;range=1..5&#39;)\n        .then(res =&gt; {\n\n        });\n</code></pre>\n      <h2 id=\"head-requests\"><code>HEAD</code> 요청하기</h2>\n      <p>\n        HEAD 요청에서도 <code>.query()</code> 메서드를 사용할 수 있습니다. 예를\n        들어 다음 코드는 <code>/users?email=joe@smith.com</code> 경로를\n        생성합니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request\n        .head(&#39;/users&#39;)\n        .query({ email: &#39;joe@smith.com&#39; })\n        .then(res =&gt; {\n\n        });\n</code></pre>\n      <h2 id=\"post--put-requests\"><code>POST</code> / <code>PUT</code> 요청</h2>\n      <p>\n        전형적인 JSON <strong>POST</strong> 요청은 Content-Type 헤더를 적절히\n        설정하고, 데이터를 JSON 형식으로 전송하는 방식입니다. 예를 들어 다음과\n        같은 코드가 이에 해당합니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n        .send(&#39;{&quot;name&quot;:&quot;tj&quot;,&quot;pet&quot;:&quot;tobi&quot;}&#39;)\n        .then(callback)\n        .catch(errorCallback)\n</code></pre>\n      <p>\n        JSON은 가장 일반적으로 사용되므로 기본값으로 설정되어 있습니다. 다음\n        예제는 앞선 예제와 동일한 동작을 수행합니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send({ name: &#39;tj&#39;, pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n      <p>또는 <code>.send()</code> 여러 번 호출할 수 있습니다.</p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send({ name: &#39;tj&#39; })\n        .send({ pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n      <p>\n        기본적으로 문자열을 전송하면 <code>Content-Type</code>이\n        <code>application/x-www-form-urlencoded</code>로 자동 설정됩니다. 여러\n        번 <code>.send()</code>를 호출하면 각 문자열이 <code>&amp;</code>로\n        연결되어 최종적으로 <code>name=tj&amp;pet=tobi</code>와 같은 결과가\n        생성됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send(&#39;name=tj&#39;)\n        .send(&#39;pet=tobi&#39;)\n        .then(callback, errorCallback);\n</code></pre>\n      <p>\n        SuperAgent는 다양한 형식으로 확장 가능하지만, 기본적으로\n        &quot;json&quot;과 &quot;form&quot; 형식을 지원합니다.\n        <code>application/x-www-form-urlencoded</code> 형식으로 데이터를\n        전송하려면 <code>.type('form')</code>을 호출하면 됩니다. 기본 형식은\n        &quot;json&quot;입니다. 다음 요청은 본문에\n        &quot;name=tj&amp;pet=tobi&quot;를 포함하여 <strong>POST</strong>됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .type(&#39;form&#39;)\n        .send({ name: &#39;tj&#39; })\n        .send({ pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n      <p>\n        <a href=\"https://developer.mozilla.org/ko/../Web/API/FormData/FormData\"\n          ><code>FormData</code></a\n        >\n        객체를 사용하는 것도 지원됩니다. 다음 예제는 id=&quot;myForm&quot;인\n        HTML 폼의 내용을 <strong>POST</strong> 방식으로 전송합니다.\n      </p>\n      <pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send(new FormData(document.getElementById(&#39;myForm&#39;)))\n        .then(callback, errorCallback)\n</code></pre>\n      <h2 id=\"setting-the-content-type\"><code>Content-Type</code> 설정하기</h2>\n      <p>\n        가장 명확한 해결책은 <code>.set()</code> 메서드를 사용하는 것입니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request.post(&#39;/user&#39;)\n       .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n</code></pre>\n      <p>\n        간단하게 <code>.type()</code> 메서드를 사용할 수 있으며, 표준화된 MIME\n        타입(<code>type/subtype</code>)을 직접 지정하거나 &quot;xml&quot;,\n        &quot;json&quot;, &quot;png&quot; 등과 같은 확장자 이름만으로도 설정할\n        수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request.post(&#39;/user&#39;)\n       .type(&#39;application/json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .type(&#39;json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .type(&#39;png&#39;)\n</code></pre>\n      <h2 id=\"serializing-request-body\">요청 본문 직렬화하기</h2>\n      <p>\n        SuperAgent는 기본적으로 JSON과 폼 데이터를 자동으로 직렬화합니다. 또한\n        다른 콘텐츠 유형에 대해서도 자동 직렬화를 설정할 수 있습니다.\n      </p>\n      <pre><code class=\"language-js\">request.serialize[&#39;application/xml&#39;] = function (obj) {\n    return &#39;string generated from obj&#39;;\n};\n\n// &#39;application/xml&#39; Content-type을 가진 모든 요청은\n// 자동으로 직렬화 됩니다.\n</code></pre>\n      <p>\n        사용자 정의 형식으로 페이로드를 전송하려면, 요청 단위로\n        <code>.serialize()</code>\n        메서드를 사용해 SuperAgent의 기본 직렬화 방식을 교체할 수 있습니다.\n      </p>\n      <pre><code class=\"language-js\">request\n    .post(&#39;/user&#39;)\n    .send({foo: &#39;bar&#39;})\n    .serialize(obj =&gt; {\n        return &#39;string generated from obj&#39;;\n    });\n</code></pre>\n      <h2 id=\"retrying-requests\">요청 재시도하기</h2>\n      <p>\n        <code>.retry()</code> 메서드를 사용하면, 일시적인 오류나 불안정한 인터넷\n        연결로 인해 요청이 실패한 경우 SuperAgent가 자동으로 재시도합니다.\n      </p>\n      <p>\n        이 메서드는 두 개의 선택적 인자를 받습니다. 재시도 횟수(기본값은 1)와\n        콜백 함수입니다. 각 재시도 전에 <code>callback(err, res)</code>를\n        호출합니다. 콜백 함수는 요청을 재시도할지 여부를 결정하기 위해\n        <code>true</code> 또는 <code>false</code>를 반환할 수 있습니다. 단, 최대\n        재시도 횟수는 항상 적용됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .get(&#39;https://example.com/search&#39;)\n       .retry(2) // 혹은\n       .retry(2, callback)\n       .then(finished);\n       .catch(failed);\n</code></pre>\n      <p>\n        멱등한 요청인 경우에만 <code>.retry()</code> 메서드를 사용하세요. 예를\n        들어, 동일한 요청이 서버에 여러 번 도달하더라도 중복 구매와 같은\n        바람직하지 않은 부작용이 발생하지 않아야 합니다.\n      </p>\n      <p>\n        모든 요청 메서드는 기본적으로 재시도 대상에 포함됩니다. 따라서 POST\n        요청을 재시도하지 않도록 하려면, 사용자 정의 재시도 콜백을 전달해야\n        합니다.\n      </p>\n      <p>기본적으로 다음과 같은 상태 코드는 자동으로 재시도됩니다.</p>\n      <ul>\n        <li><code>408</code></li>\n        <li><code>413</code></li>\n        <li><code>429</code></li>\n        <li><code>500</code></li>\n        <li><code>502</code></li>\n        <li><code>503</code></li>\n        <li><code>504</code></li>\n        <li><code>521</code></li>\n        <li><code>522</code></li>\n        <li><code>524</code></li>\n      </ul>\n      <p>기본적으로 다음과 같은 오류 코드가 자동으로 재시도됩니다.</p>\n      <ul>\n        <li><code>&#39;ETIMEDOUT&#39;</code></li>\n        <li><code>&#39;ECONNRESET&#39;</code></li>\n        <li><code>&#39;EADDRINUSE&#39;</code></li>\n        <li><code>&#39;ECONNREFUSED&#39;</code></li>\n        <li><code>&#39;EPIPE&#39;</code></li>\n        <li><code>&#39;ENOTFOUND&#39;</code></li>\n        <li><code>&#39;ENETUNREACH&#39;</code></li>\n        <li><code>&#39;EAI_AGAIN&#39;</code></li>\n      </ul>\n      <h2 id=\"setting-accept\">Accept 설정하기</h2>\n      <p>\n        <code>.type()</code> 메서드와 유사하게, <code>.accept()</code> 메서드를\n        사용하면 <code>Accept</code> 헤더를 간편하게 설정할 수 있습니다. 이\n        메서드는 <code>request.types</code>를 참조하며,\n        <code>type/subtype</code> 형식의 MIME 타입 전체 이름이나\n        &quot;xml&quot;, &quot;json&quot;, &quot;png&quot; 등의 확장자 형태로도\n        지정할 수 있어 편리합니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request.get(&#39;/user&#39;)\n       .accept(&#39;application/json&#39;)\n\n     request.get(&#39;/user&#39;)\n       .accept(&#39;json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .accept(&#39;png&#39;)\n</code></pre>\n      <h3 id=\"facebook-and-accept-json\">Facebook과 Accept JSON</h3>\n      <p>\n        Facebook API를 호출할 때는 반드시 요청 헤더에\n        <code>Accept: application/json</code>을 포함해야 합니다. 그렇지 않으면\n        Facebook은 <code>Content-Type: text/javascript; charset=UTF-8</code>으로\n        응답하게 되며, SuperAgent는 이 형식을 파싱하지 못해\n        <code>res.body</code>가 undefined가 됩니다.\n        <code>req.accept(&#39;json&#39;)</code> 또는\n        <code>req.set(&#39;Accept&#39;, &#39;application/json&#39;)</code>을\n        사용할 수 있습니다. 자세한 사항은\n        <a href=\"https://github.com/ladjs/superagent/issues/1078\">issue 1078</a>\n        에서 확인해보세요.\n      </p>\n      <h2 id=\"query-strings\">쿼리 문자열</h2>\n      <p>\n        <code>req.query(obj)</code>는 쿼리 문자열을 구성하는 데 사용되는\n        메서드입니다. 예를 들어 <strong>POST</strong> 요청에서\n        <code>?format=json&amp;dest=/login</code>과 같은 쿼리 문자열을 추가할 수\n        있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .post(&#39;/&#39;)\n      .query({ format: &#39;json&#39; })\n      .query({ dest: &#39;/login&#39; })\n      .send({ post: &#39;data&#39;, here: &#39;wahoo&#39; })\n      .then(callback);\n</code></pre>\n      <p>\n        기본적으로 쿼리 문자열은 특정한 순서로 조립되지 않습니다. ASCII 순으로\n        정렬된 쿼리 문자열을 사용하려면\n        <code>req.sortQuery()</code>를 호출하면 됩니다. 또한\n        <code>req.sortQuery(myComparisonFn)</code>을 통해 사용자 정의 정렬 비교\n        함수를 전달할 수도 있습니다. 비교 함수는 두 개의 인자를 받아 음수, 0\n        또는 양수를 반환해야 합니다.\n      </p>\n      <pre><code class=\"language-js\"> // 기본 정렬 방식\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery()\n   .then(callback)\n\n // 사용자 정의 정렬 함수\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery((a, b) =&gt; a.length - b.length)\n   .then(callback)\n</code></pre>\n      <h2 id=\"tls-options\">TLS 옵션</h2>\n      <p>\n        Node.js에서 SuperAgent는 HTTPS 요청을 구성할 수 있는 다양한 메서드를\n        지원합니다.\n      </p>\n      <ul>\n        <li><code>.ca()</code>: 신뢰할 CA 인증서를 설정합니다.</li>\n        <li><code>.cert()</code>: 클라이언트 인증서 체인을 설정합니다.</li>\n        <li><code>.key()</code>: 클라이언트의 개인 키를 설정합니다.</li>\n        <li>\n          <code>.pfx()</code>: PKCS12 형식의 PFX 파일을 사용하여 클라이언트의\n          개인 키와 인증서 체인을 설정합니다.\n        </li>\n        <li>\n          <code>.disableTLSCerts()</code>: 만료되었거나 유효하지 않은 TLS\n          인증서를 거부하지 않도록 설정합니다. 내부적으로\n          <code>rejectUnauthorized=true</code>가 설정되며, 중간자 공격(MITM)에\n          노출될 수 있으므로 주의가 필요합니다.\n        </li>\n      </ul>\n      <p>\n        더 자세한 내용은 Node.js\n        <a\n          href=\"https://nodejs.org/api/https.html#https_https_request_options_callback\"\n          >https.request 문서</a\n        >에서 확인할 수 있습니다.\n      </p>\n      <pre><code class=\"language-js\">var key = fs.readFileSync(&#39;key.pem&#39;),\n    cert = fs.readFileSync(&#39;cert.pem&#39;);\n\nrequest\n  .post(&#39;/client-auth&#39;)\n  .key(key)\n  .cert(cert)\n  .then(callback);\n</code></pre>\n      <pre><code class=\"language-js\">var ca = fs.readFileSync(&#39;ca.cert.pem&#39;);\n\nrequest\n  .post(&#39;https://localhost/private-ca-server&#39;)\n  .ca(ca)\n  .then(res =&gt; {});\n</code></pre>\n      <h2 id=\"parsing-response-bodies\">응답 본문 파싱하기</h2>\n      <p>\n        SuperAgent는 응답 본문 데이터를 자동으로 파싱해줍니다. 현재\n        <code>application/x-www-form-urlencoded</code>,\n        <code>application/json</code>, <code>multipart/form-data</code>을\n        지원합니다. 이외의 응답 본문 데이터에 대해서도 자동 파싱을 설정할 수\n        있습니다.\n      </p>\n      <pre><code class=\"language-js\">// 브라우저\nrequest.parse[&#39;application/xml&#39;] = function (str) {\n    return {&#39;object&#39;: &#39;parsed from str&#39;};\n};\n\n// node\nrequest.parse[&#39;application/xml&#39;] = function (res, cb) {\n    //parse response text and set res.body here\n\n    cb(null, res);\n};\n\n// 앞으로 &#39;application/xml&#39; 유형의 반응은\n// 자동으로 파싱됩니다\n</code></pre>\n      <p>\n        <code>.buffer(true).parse(fn)</code> 메서드를 사용하면 내장된 파서보다\n        우선적으로 적용되는 사용자 정의 파서를 설정할 수 있습니다.\n        <code>.buffer(false)</code>로 응답 버퍼링이 비활성화되어 있다면,\n        <code>response</code> 이벤트는 본문 파싱이 완료되기 전에 발생하므로\n        <code>response.body</code>를 사용할 수 없습니다.\n      </p>\n      <h3 id=\"json--urlencoded\">JSON / Urlencoded</h3>\n      <p>\n        <code>res.body</code> 속성은 파싱된 객체를 나타냅니다. 예를 들어, 응답이\n        JSON 문자열\n        &#39;{&quot;user&quot;:{&quot;name&quot;:&quot;tobi&quot;}}&#39;를\n        반환했다면, <code>res.body.user.name</code>은 &quot;tobi&quot; 값을 갖게\n        됩니다. 마찬가지로 x-www-form-urlencoded 형식의\n        &quot;user[name]=tobi&quot;도 동일한 결과를 제공합니다. 단, 중첩은 한\n        단계까지만 지원되므로 더 복잡한 구조의 데이터를 다루려면 JSON 형식을\n        사용하는 것이 좋습니다.\n      </p>\n      <p>\n        배열은 key를 반복해서 전달하는 방식으로 전송됩니다.\n        <code>.send({color: [&#39;red&#39;,&#39;blue&#39;]})</code>는\n        <code>color=red&amp;color=blue</code>로 변환되어 전송됩니다. 배열의\n        key에 <code>[]</code>를 포함시키고 싶다면 SuperAgent는 이를 자동으로\n        처리하지 않으므로, 직접 <code>color[]</code>와 같이 key 이름에 대괄호를\n        추가해야 합니다.\n      </p>\n      <h3 id=\"multipart\">다중 파트</h3>\n      <p>\n        Node 클라이언트는\n        <a href=\"https://github.com/felixge/node-formidable\">Formidable</a>\n        모듈을 통해 <em>multipart/form-data</em>를 지원합니다. 다중 파트 응답을\n        파싱할 때 <code>res.files</code> 객체를 사용할 수 있으며, 이 객체에는\n        업로드된 파일에 대한 정보가 포함됩니다. 예를 들어, 다음과 같은 multipart\n        본문을 포함한 응답을 가정해볼 수 있습니다.\n      </p>\n      <pre><code>--whoop\nContent-Disposition: attachment; name=&quot;image&quot;; filename=&quot;tobi.png&quot;\nContent-Type: image/png\n\n... data here ...\n--whoop\nContent-Disposition: form-data; name=&quot;name&quot;\nContent-Type: text/plain\n\nTobi\n--whoop--\n</code></pre>\n      <p>\n        <code>res.body.name</code>은 &quot;Tobi&quot; 값을 가지고 있으며,\n        <code>res.files.image</code>는 디스크 경로, 파일 이름 및 기타 속성을\n        포함한 <code>File</code> 객체입니다.\n      </p>\n      <h3 id=\"binary\">바이너리</h3>\n      <p>\n        브라우저에서는 바이너리 응답 본문을 처리하기 위해\n        <code>.responseType(&#39;blob&#39;)</code>을 사용할 수 있습니다. 이\n        API는 Node.js 환경에서는 필요하지 않습니다. 이 메서드에서 지원되는 인자\n        값은 다음과 같습니다.\n      </p>\n      <ul>\n        <li>\n          <code>&#39;blob&#39;</code>는 XMLHttpRequest의\n          <code>responseType</code> 속성에 그대로 전달됩니다.\n        </li>\n        <li>\n          <code>&#39;arraybuffer&#39;</code>도 마찬가지로\n          <code>responseType</code> 속성에 전달됩니다.\n        </li>\n      </ul>\n      <pre><code class=\"language-js\">req.get(&#39;/binary.data&#39;)\n  .responseType(&#39;blob&#39;)\n  .then(res =&gt; {\n    // 여기서 res.body는 브라우저 기본 Blob 타입입니다.\n  });\n</code></pre>\n      <p>\n        더 자세한 내용은 Mozilla Developer Network의\n        <a\n          href=\"https://developer.mozilla.org/en-US/../Web/API/XMLHttpRequest/responseType\"\n          >XMLHttpRequest.responseType 문서</a\n        >에서 확인할 수 있습니다.\n      </p>\n      <h2 id=\"response-properties\">응답 속성</h2>\n      <p>\n        <code>Response</code> 객체에는 응답 텍스트, 파싱된 응답 본문, 헤더 필드,\n        상태 플래그 등 다양한 유용한 플래그와 속성이 설정되어 있습니다.\n      </p>\n      <h3 id=\"response-text\">응답 문자</h3>\n      <p>\n        <code>res.text</code> 속성에는 파싱되지 않은 응답 본문 문자열이\n        포함됩니다. 이 속성은 클라이언트 API에서는 항상 존재하며, Node\n        환경에서는 MIME 타입이 &quot;text/<em>&quot;, &quot;</em>/json&quot;,\n        또는 &quot;x-www-form-urlencoded&quot;와 일치할 경우에만 기본적으로\n        제공됩니다. 이러한 제한은 대용량 multipart 파일이나 이미지 등의 본문을\n        텍스트로 버퍼링하는 것이 매우 비효율적이기 때문에 메모리를 절약하기 위한\n        목적입니다. 응답을 강제로 버퍼링하려면 &quot;응답 버퍼링&quot; 섹션을\n        참조하세요.\n      </p>\n      <h3 id=\"response-body\">응답 본문</h3>\n      <p>\n        SuperAgent는 요청 데이터를 자동으로 직렬화할 뿐만 아니라, 자동으로\n        파싱할 수도 있습니다. Content-Type에 대해 파서가 정의되어 있는 경우,\n        해당 타입에 맞게 응답이 파싱되며 기본적으로\n        &quot;application/json&quot;과\n        &quot;application/x-www-form-urlencoded&quot; 형식이 포함됩니다. 파싱된\n        객체는 <code>res.body</code>를 통해 접근할 수 있습니다.\n      </p>\n      <h3 id=\"response-header-fields\">응답 헤더 필드</h3>\n      <p>\n        <code>res.header</code>는 파싱된 응답 헤더 필드를 담은 객체로, Node.js와\n        마찬가지로 필드 이름을 소문자로 변환하여 저장합니다. 예를 들어,\n        <code>res.header[&#39;content-length&#39;]</code>와 같이 접근할 수\n        있습니다.\n      </p>\n      <h3 id=\"response-content-type\">응답 콘텐츠 타입</h3>\n      <p>\n        Content-Type 응답 헤더는 특별하게 처리되어 <code>res.type</code> 속성은\n        charset 정보를 제외한 콘텐츠 타입만을 제공합니다. 예를 들어\n        Content-Type이 &quot;text/html; charset=utf8&quot;인 경우,\n        <code>res.type</code>은 &quot;text/html&quot;을 반환하고,\n        <code>res.charset</code> 속성에는 &quot;utf8&quot;이 포함됩니다.\n      </p>\n      <h3 id=\"response-status\">응답 상태</h3>\n      <p>\n        응답 상태 플래그는 요청이 성공했는지 여부를 비롯한 다양한 유용한 정보를\n        판단하는 데 도움을 줍니다. 이를 통해 SuperAgent는 RESTful 웹 서비스와\n        효과적으로 상호작용할 수 있습니다. 현재 정의된 주요 플래그는 다음과\n        같습니다.\n      </p>\n      <pre><code class=\"language-javascript\">     var type = status / 100 | 0;\n\n     // 상태 / 클래스\n     res.status = status;\n     res.statusType = type;\n\n     // 기본\n     res.info = 1 == type;\n     res.ok = 2 == type;\n     res.clientError = 4 == type;\n     res.serverError = 5 == type;\n     res.error = 4 == type || 5 == type;\n\n     // 편의 기능\n     res.accepted = 202 == status;\n     res.noContent = 204 == status || 1223 == status;\n     res.badRequest = 400 == status;\n     res.unauthorized = 401 == status;\n     res.notAcceptable = 406 == status;\n     res.notFound = 404 == status;\n     res.forbidden = 403 == status;\n</code></pre>\n      <h2 id=\"aborting-requests\">요청 중단하기</h2>\n      <p>\n        요청을 중단하려면 <code>req.abort()</code> 메서드를 호출하기만 하면\n        됩니다.\n      </p>\n      <h2 id=\"timeouts\">타임아웃</h2>\n      <p>\n        때때로 네트워크나 서버가 요청을 수신한 후 응답 없이 멈춰버리는 경우가\n        있습니다. 이러한 무한 대기를 방지하려면 타임아웃을 설정해야 합니다.\n      </p>\n      <ul>\n        <li>\n          <p>\n            <code>req.timeout({deadline:ms})</code> 또는\n            <code>req.timeout(ms)</code>는 업로드, 리다이렉트, 서버 처리 시간을\n            포함한 전체 요청이 완료되어야 하는 최종 시간 제한을 설정합니다.\n            <code>ms</code>는 0보다 큰 밀리초 단위의 숫자이며, 제한 시간 내에\n            응답이 완료되지 않으면 요청은 중단됩니다.\n          </p>\n        </li>\n        <li>\n          <p>\n            <code>req.timeout({response:ms})</code>는 서버로부터 첫 번째\n            바이트가 도착할 때까지의 최대 대기 시간을 설정합니다. 전체 다운로드\n            소요 시간은 제한하지 않습니다. 응답 타임아웃은 DNS 조회, TCP/IP 및\n            TLS 연결, 요청 데이터 업로드 시간을 포함하므로, 서버의 실제 응답\n            시간보다 몇 초 더 길게 설정하는 것이 좋습니다.\n          </p>\n        </li>\n      </ul>\n      <p>\n        <code>deadline</code>과 <code>response</code> 타임아웃은 함께 사용하는\n        것이 좋습니다. 짧은 응답 타임아웃은 응답하지 않는 네트워크를 빠르게\n        감지하는 데 유용하고, 긴 데드라인은 느리지만 안정적인 네트워크 환경에서\n        다운로드를 완료할 수 있도록 여유 시간을 제공합니다. 두 타이머 모두\n        첨부된 파일 업로드에 허용되는 시간을 제한합니다. 파일을 업로드하는\n        경우에는 충분히 긴 타임아웃을 설정하는 것이 좋습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .get(&#39;/big-file?network=slow&#39;)\n      .timeout({\n        response: 5000,  // 서버가 데이터를 보내기 시작할 때까지 최대 5초간 기다립니다.\n        deadline: 60000, // 파일 전체를 로드하는 데 최대 1분까지 허용합니다.\n      })\n      .then(res =&gt; {\n          /* 제시간 응답 수신 */\n        }, err =&gt; {\n          if (err.timeout) { /* 시간 초과! */ } else { /* 그 외 오류 */ }\n      });\n</code></pre>\n      <p>타임아웃 오류에는 <code>.timeout</code> 속성이 포함되어 있습니다.</p>\n      <h2 id=\"authentication\">인증</h2>\n      <p>\n        Node와 브라우저 환경에서 <code>.auth()</code> 메서드를 사용하여 인증을\n        수행할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .get(&#39;http://local&#39;)\n      .auth(&#39;tobi&#39;, &#39;learnboost&#39;)\n      .then(callback);\n</code></pre>\n      <p>\n        <em>Node</em> 클라이언트에서는 기본 인증을 URL 내에\n        &quot;user:pass&quot; 형식으로 포함시킬 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request.get(&#39;http://tobi:learnboost@local&#39;).then(callback);\n</code></pre>\n      <p>\n        기본적으로 <code>Basic</code> 인증만 사용됩니다. 브라우저에서는\n        <code>{type:&#39;auto&#39;}</code>를 추가하면 Digest, NTLM 등 브라우저에\n        내장된 모든 인증 방식을 사용할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request.auth(&#39;digest&#39;, &#39;secret&#39;, {type:&#39;auto&#39;})\n</code></pre>\n      <p>\n        <code>auth</code> 메서드는 토큰 기반 인증을 위한 <code>type</code>의\n        <code>bearer</code> 옵션도 지원합니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request.auth(&#39;my_token&#39;, { type: &#39;bearer&#39; })\n</code></pre>\n      <h2 id=\"following-redirects\">다음 리다이렉션 따라가기</h2>\n      <p>\n        기본적으로 최대 5번까지 리다이렉션이 자동으로 따라가며, 필요에 따라\n        <code>res.redirects(n)</code> 메서드를 사용하여 이 횟수를 지정할 수\n        있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const response = await request.get(&#39;/some.png&#39;).redirects(2);\n</code></pre>\n      <p>\n        리다이렉션 횟수가 제한을 초과하면 오류로 간주됩니다. 이를 성공적인\n        응답으로 처리하려면\n        <code>.ok(res =&gt; res.status &lt; 400)</code> 메서드를 사용하세요.\n      </p>\n      <h2 id=\"agents-for-global-state\">전역 상태를 위한 에이전트</h2>\n      <h3 id=\"saving-cookies\">쿠키 저장하기</h3>\n      <p>\n        Node에서 SuperAgent는 기본적으로 쿠키를 저장하지 않습니다. 하지만\n        <code>.agent()</code> 메서드를 사용하면 쿠키를 저장하는 SuperAgent\n        인스턴스를 생성할 수 있습니다. 각 인스턴스는 독립적인 쿠키 저장소를\n        가지고 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const agent = request.agent();\n    agent\n      .post(&#39;/login&#39;)\n      .then(() =&gt; {\n        return agent.get(&#39;/cookied-page&#39;);\n      });\n</code></pre>\n      <p>\n        브라우저에서는 쿠키가 자동으로 관리되므로\n        <code>.agent()</code>를 사용해도 쿠키가 분리되지는 않습니다.\n      </p>\n      <h3 id=\"default-options-for-multiple-requests\">\n        다중 요청을 위한 기본 옵션\n      </h3>\n      <p>\n        에이전트에서 호출된 일반 요청 메서드는 해당 에이전트가 처리하는 모든\n        요청에 대해 기본값으로 적용됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const agent = request.agent()\n      .use(plugin)\n      .auth(shared);\n\n    await agent.get(&#39;/with-plugin-and-auth&#39;);\n    await agent.get(&#39;/also-with-plugin-and-auth&#39;);\n</code></pre>\n      <p>\n        에이전트가 기본 옵션을 설정할 수 있도록 지원하는 메서드 목록입니다.\n        <code>use</code>, <code>on</code>, <code>once</code>, <code>set</code>,\n        <code>query</code>, <code>type</code>, <code>accept</code>,\n        <code>auth</code>, <code>withCredentials</code>, <code>sortQuery</code>,\n        <code>retry</code>, <code>ok</code>, <code>redirects</code>,\n        <code>timeout</code>, <code>buffer</code>, <code>serialize</code>,\n        <code>parse</code>, <code>ca</code>, <code>key</code>, <code>pfx</code>,\n        <code>cert</code>.\n      </p>\n      <h2 id=\"piping-data\">데이터 전달 방식</h2>\n      <p>\n        <code>.pipe()</code>는 <code>.end()</code> 또는\n        <code>.then()</code> 메서드 <strong>대신</strong> 사용되며, Node\n        클라이언트는 요청과 응답 간에 데이터를 주고받도록 파이프 처리할 수\n        있습니다.\n      </p>\n      <p>\n        예를 들어, 파일의 콘텐츠를 요청 본문으로 전달하는 경우는 다음과\n        같습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const request = require(&#39;superagent&#39;);\n    const fs = require(&#39;fs&#39;);\n\n    const stream = fs.createReadStream(&#39;path/to/my.json&#39;);\n    const req = request.post(&#39;/somewhere&#39;);\n    req.type(&#39;json&#39;);\n    stream.pipe(req);\n</code></pre>\n      <p>\n        요청에 데이터를 파이프할 경우, SuperAgent는 해당 데이터를\n        <a href=\"https://en.wikipedia.org/wiki/Chunked_transfer_encoding\"\n          >청크 전송 인코딩</a\n        >\n        방식으로 전송합니다. 이 방식은 Python WSGI 서버 등 모든 서버에서\n        지원되지는 않습니다.\n      </p>\n      <p>응답을 파일로 저장하려면 다음과 같이 파이프 처리할 수 있습니다.</p>\n      <pre><code class=\"language-javascript\">    const stream = fs.createWriteStream(&#39;path/to/my.json&#39;);\n    const req = request.get(&#39;/some.json&#39;);\n    req.pipe(stream);\n</code></pre>\n      <p>\n        파이프와 콜백 또는 프로미스는 <strong>함께 사용할 수 없으며</strong>,\n        <code>.end()</code>나 <code>Response</code> 객체의 결과를 파이프\n        처리해서는 안 됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">    // 이러한 방식으로 하지 마세요.\n    const stream = getAWritableStream();\n    const req = request\n      .get(&#39;/some.json&#39;)\n      // 나쁨: 이 방식은 스트림에 올바르지 않은 데이터를 전달하며 예기치 못한 방식으로 실패할 수 있습니다.\n      .end((err, this_does_not_work) =&gt; this_does_not_work.pipe(stream))\n    const req = request\n      .get(&#39;/some.json&#39;)\n      .end()\n      // 나쁨: 이 방식도 지원되지 않으며, .pipe는 자동으로 .end를 호출합니다.\n      .pipe(nope_its_too_late);\n</code></pre>\n      <p>\n        SuperAgent의\n        <a href=\"https://github.com/ladjs/superagent/issues/1188\">향후 버전</a\n        >에서는 <code>pipe()</code>를 부적절하게 호출하면 실패하게 됩니다.\n      </p>\n      <h2 id=\"multipart-requests\">다중 부분 요청</h2>\n      <p>\n        <code>.attach()</code>와 <code>.field()</code> 메서드를 제공하는\n        SuperAgent는 다중 부분 요청을 구성하는 데에도 매우 유용합니다.\n      </p>\n      <p>\n        <code>.field()</code> 또는 <code>.attach()</code>를 사용할 경우\n        <code>.send()</code>는 사용할 수 없으며,\n        <code>Content-Type</code> 헤더를 직접 설정해서는 안 됩니다. 올바른\n        타입은 자동으로 지정됩니다.\n      </p>\n      <h3 id=\"attaching-files\">파일 첨부하기</h3>\n      <p>\n        <code>.attach(name, [file], [options])</code>를 사용하여 파일을 전송할\n        수 있습니다. 여러 파일을 첨부하려면 <code>.attach</code>를 반복 호출하면\n        됩니다. 인자는 다음과 같습니다.\n      </p>\n      <ul>\n        <li><code>name</code> — 폼 이름 필드.</li>\n        <li>\n          <code>file</code> — 파일 경로의 문자열 또는 <code>Blob</code>/<code\n            >Buffer</code\n          >\n          객체.\n        </li>\n        <li>\n          <code>options</code> — (선택) 사용자 정의 파일 이름의 문자열 또는\n          <code>{filename: string}</code> 형식의 객체. In Node also\n          <code>{contentType: &#39;mime/type&#39;}</code> is supported. In\n          browser create a <code>Blob</code> with an appropriate type instead.\n        </li>\n      </ul>\n      <br />\n\n      <pre><code class=\"language-javascript\">    request\n      .post(&#39;/upload&#39;)\n      .attach(&#39;image1&#39;, &#39;path/to/felix.jpeg&#39;)\n      .attach(&#39;image2&#39;, imageBuffer, &#39;luna.jpeg&#39;)\n      .field(&#39;caption&#39;, &#39;My cats&#39;)\n      .then(callback);\n</code></pre>\n      <h3 id=\"field-values\">필드 값</h3>\n      <p>\n        <code>.field(name, value)</code> 및 <code>.field({name: value})</code>를\n        사용해 HTML 폼 필드처럼 값을 설정할 수 있습니다. 예를 들어 이름과 이메일\n        정보를 함께 여러 이미지를 업로드하려면, 요청은 다음과 같이 구성될 수\n        있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">     request\n       .post(&#39;/upload&#39;)\n       .field(&#39;user[name]&#39;, &#39;Tobi&#39;)\n       .field(&#39;user[email]&#39;, &#39;tobi@learnboost.com&#39;)\n       .field(&#39;friends[]&#39;, [&#39;loki&#39;, &#39;jane&#39;])\n       .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n       .then(callback);\n</code></pre>\n      <h2 id=\"compression\">압축</h2>\n      <p>\n        node 클라이언트는 압축된 응답을 지원하며, 아무 것도 하지 않아도 됩니다!\n        그냥 작동합니다.\n      </p>\n      <h2 id=\"buffering-responses\">응답 버퍼링</h2>\n      <p>\n        <code>.req.buffer()</code>를 호출하면 응답 본문을\n        <code>res.text</code>로 강제 버퍼링할 수 있습니다.\n        &quot;text/plain&quot;, &quot;text/html&quot; 등 텍스트 응답의 기본\n        버퍼링을 취소하려면 <code>req.buffer(false)</code>를 호출하세요.\n      </p>\n      <p>\n        <code>res.buffered</code> 플래그가 제공되면, 이를 활용하여 동일한 콜백\n        함수에서 버퍼링된 응답과 버퍼링되지 않은 응답을 모두 처리할 수 있습니다.\n      </p>\n      <h2 id=\"cors\">CORS</h2>\n      <p>\n        보안상의 이유로 브라우저는 서버가 CORS 헤더를 통해 명시적으로 허용하지\n        않으면 교차 출처 요청(cross-origin requests)을 차단합니다. 브라우저는\n        또한 서버가 어떤 HTTP 헤더와 메서드를 허용하는지 확인하기 위해 추가적인\n        <strong>OPTIONS</strong> 요청을 전송합니다.\n        <a\n          href=\"https://developer.mozilla.org/ko/../Web/HTTP/Access_control_CORS\"\n          >CORS에 대해 더 알아보기</a\n        >.\n      </p>\n      <p>\n        <code>.withCredentials()</code> 메서드는 origin(출처)에서 쿠키를 전송할\n        수 있도록 활성화합니다. 단, 이 기능은\n        <code>Access-Control-Allow-Origin</code> 값이\n        와일드카드(&quot;*&quot;)가 <em>아니어야</em> 하며,\n        <code>Access-Control-Allow-Credentials</code> 값이 &quot;true&quot;일\n        경우에만 작동합니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .get(&#39;https://api.example.com:4001/&#39;)\n      .withCredentials()\n      .then(res =&gt; {\n        assert.equal(200, res.status);\n        assert.equal(&#39;tobi&#39;, res.text);\n      })\n</code></pre>\n      <h2 id=\"error-handling\">오류 처리하기</h2>\n      <p>\n        콜백 함수는 항상 두 개의 인자를 전달합니다. 오류와 응답입니다. 오류가\n        발생하지 않으면, 첫 번째 인자는 null 입니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n     .post(&#39;/upload&#39;)\n     .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n     .then(res =&gt; {\n\n     });\n</code></pre>\n      <p>\n        \"error\" 이벤트도 발생하며, 이를 통해 오류를 감지하고 처리할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request\n      .post(&#39;/upload&#39;)\n      .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n      .on(&#39;error&#39;, handle)\n      .then(res =&gt; {\n\n      });\n</code></pre>\n      <p>\n        <strong\n          >SuperAgent는 기본적으로 4xx 및 5xx 응답(그리고 처리되지 않은 3xx\n          응답도 포함)을 오류</strong\n        >로 간주합니다. 예를 들어 <code>304 Not Modified</code>,\n        <code>403 Forbidden</code> 또는\n        <code>500 Internal Server Error</code> 같은 응답을 받으면 해당 상태\n        정보는 <code>err.status</code>를 통해 확인할 수 있습니다. 이러한\n        응답으로부터 발생한 오류에는 &quot;<a href=\"#response-properties\"\n          >응답 요소</a\n        >&quot;에서 언급한 모든 속성을 포함한 <code>err.response</code> 필드도\n        포함됩니다. 이 라이브러리는 일반적으로 성공 응답만을 원하고, HTTP 오류\n        상태 코드를 오류로 처리하는 경우를 대비하여 이러한 방식으로 동작합니다.\n        하지만 특정 오류 조건에 대해서는 사용자 정의 로직을 허용하도록 설계되어\n        있습니다.\n      </p>\n      <p>\n        네트워크 실패, 시간초과, 응답 없는 오류는 <code>err.status</code> 또는\n        <code>err.response</code> 필드를 포함하지 않습니다.\n      </p>\n      <p>\n        404 또는 HTTP 오류 응답을 처리하고 싶다면,\n        <code>error.status</code> 요소를 사용할 수 있습니다. HTTP 오류(4xx 또는\n        5xx 응답)가 발생했을 때 <code>res.error</code> 요소는\n        <code>Error</code> 객체이고 이는 다음과 같이 에러 확인을 수행할 수\n        있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    if (err &amp;&amp; err.status === 404) {\n      alert(&#39;oh no &#39; + res.body.message);\n    }\n    else if (err) {\n      // 그 외 다른 모든 오류 유형은 일반적으로 처리합니다\n    }\n</code></pre>\n      <p>\n        대안으로, <code>.ok(callback)</code> 메서드를 사용하여 응답이 오류인지\n        아닌지 결정할 수 있습니다. <code>ok</code> 콜백은 응답을 받고 응답이\n        성공으로 해석되면 <code>true</code>를 반환합니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request.get(&#39;/404&#39;)\n      .ok(res =&gt; res.status &lt; 500)\n      .then(response =&gt; {\n        // 404 페이지를 성공적인 응답으로 처리합니다\n      })\n</code></pre>\n      <h2 id=\"progress-tracking\">진행과정 추적하기</h2>\n      <p>\n        SuperAgent는 업로드와 큰 파일 다운로드에서\n        <code>progress</code> 이벤트를 동작시킵니다.\n      </p>\n      <pre><code class=\"language-javascript\">    request.post(url)\n      .attach(&#39;field_name&#39;, file)\n      .on(&#39;progress&#39;, event =&gt; {\n        /* the event is:\n        {\n          direction: &quot;upload&quot; or &quot;download&quot;\n          percent: 0 to 100 // 0에서 100까지 (파일 크기를 알 수 없는 경우 생략될 수 있습니다)\n          total: // 전체 파일 크기 (생략될 수 있습니다)\n          loaded: // 현재까지 다운로드되거나 업로드된 바이트 수\n        } */\n      })\n      .then()\n</code></pre>\n      <h2 id=\"testing-on-localhost\">로컬 호스트에서 테스트하기</h2>\n      <h3 id=\"forcing-specific-connection-ip-address\">\n        특정 IP 주소 연결 설정하기\n      </h3>\n      <p>\n        Node.js에서는 DNS를 무시하고 <code>.connect()</code> 메서드를 사용하여\n        모든 요청을 특정 IP 주소로 직접 연결할 수 있습니다. 예를 들어, 이 요청은\n        <code>example.com</code> 대신 로컬호스트로 전달됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const res = await request.get(&quot;http://example.com&quot;).connect(&quot;127.0.0.1&quot;);\n</code></pre>\n      <p>\n        요청은 리다이렉트 되어, 여러 호스트명과 IP를 특정지을 수 있으며 특별한\n        <code>*</code>를 대체로 설정할 수 있습니다. (다른 와일드 카드는 지원되지\n        않습니다). 요청은 원본 값을 가지며 본인의 <code>Host</code> 헤더를\n        유지합니다. <code>.connect(undefined)</code>는 이러한 기능을 끕니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const res = await request.get(&quot;http://redir.example.com:555&quot;)\n      .connect({\n        &quot;redir.example.com&quot;: &quot;127.0.0.1&quot;, // redir.example.com:555는 127.0.0.1:555를 사용합니다.\n        &quot;www.example.com&quot;: false, // 이 항목은 재정의하지 마세요. 일반적인 DNS 설정을 사용합니다.\n        &quot;mapped.example.com&quot;: { host: &quot;127.0.0.1&quot;, port: 8080}, // mapped.example.com의 모든 포트는 127.0.0.1:8080으로 매핑됩니다.\n        &quot;*&quot;: &quot;proxy.example.com&quot;, // 나머지 모든 요청은 이 호스트로 전달됩니다\n      });\n</code></pre>\n      <h3 id=\"ignoring-brokeninsecure-https-on-localhost\">\n        로컬 호스트에서 깨지거나 보안되지 않은 HTTPS 무시하기\n      </h3>\n      <p>\n        Node.js에서 HTTPS 설정이 잘못되었거나 보안성이 떨어지는 경우(예: 자체\n        서명된 인증서를 사용하면서\n        <code>.ca()</code>를 지정하지 않은 경우),\n        <code>.trustLocalhost()</code>를 호출하면 <code>localhost</code>로의\n        요청을 허용할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const res = await request.get(&quot;https://localhost&quot;).trustLocalhost()\n</code></pre>\n      <p>\n        <code>.connect(&quot;127.0.0.1&quot;)</code>와 함께 사용하면 HTTPS\n        요청을 어떤 도메인에서든 <code>localhost</code>로 강제로 리다이렉트할 수\n        있습니다.\n      </p>\n      <p>\n        <code>localhost</code>는 신뢰되지 않은 네트워크에 노출되지 않는 루프백\n        인터페이스이기 때문에, 깨진 HTTPS를 무시하는 것이 일반적으로 안전합니다.\n        <code>localhost</code>를 신뢰하도록 설정하는 것이 향후 기본값이 될 수\n        있습니다. <code>127.0.0.1</code>&#39;의 진위 여부를 강제로 검사하려면\n        <code>.trustLocalhost(false)</code>를 사용하세요.\n      </p>\n      <p>\n        다른 IP 주소로 요청을 보낼 때 HTTPS 보안을 비활성화하는 기능은\n        의도적으로 지원하지 않습니다. 이러한 옵션은 HTTPS 문제를 빠르게\n        &quot;해결&quot;하려는 방식으로 오용되는 경우가 많기 때문입니다.\n        <a href=\"https://certbot.eff.org\">Let&#39;s Encrypt</a>를 통해 무료\n        HTTPS 인증서를 발급하거나, <code>.ca(ca_public_pem)</code>을 사용해 자체\n        서명된 인증서를 신뢰할 수 있도록 직접 CA를 설정할 수 있습니다.\n      </p>\n      <h2 id=\"promise-and-generator-support\">Promise 및 Generator 지원</h2>\n      <p>\n        SuperAgent의 요청은 &quot;thenable&quot; 객체이며, JavaScript의 Promise\n        및 <code>async</code>/<code>await</code>\n        문법과 호환됩니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const res = await request.get(url);\n</code></pre>\n      <p>\n        Promise를 사용할 경우,\n        <strong\n          ><code>.end()</code> 또는 <code>.pipe()</code>를 호출하지\n          마세요</strong\n        >. <code>.then()</code> 또는 <code>await</code>를 사용하면 요청을 처리할\n        수 있는 다른 방식들이 모두 비활성화됩니다.\n      </p>\n      <p>\n        <a href=\"https://github.com/tj/co\">co</a>와 같은 라이브러리나\n        <a href=\"https://github.com/koajs/koa\">koa</a>와 같은 웹\n        프레임워크에서는 SuperAgent의 모든 메서드에서 <code>yield</code>를\n        사용할 수 있습니다.\n      </p>\n      <pre><code class=\"language-javascript\">    const req = request\n      .get(&#39;http://local&#39;)\n      .auth(&#39;tobi&#39;, &#39;learnboost&#39;);\n    const res = yield req;\n</code></pre>\n      <p>\n        SuperAgent는 전역 <code>Promise</code> 객체가 존재하는 환경에서\n        동작하도록 설계되어 있습니다. Internet Explorer나 Node.js 0.10에서\n        promise를 사용하려면 v7 버전과 폴리필이 필요합니다.\n      </p>\n      <p>\n        v8 버전부터는 IE에 대한 지원이 중단되었습니다. Opera 85나 iOS Safari\n        12.2–12.5 등을 지원하려면 WeakRef와 BigInt에 대한 폴리필을 추가해야\n        합니다. 예를 들어\n        <a href=\"https://cdnjs.cloudflare.com/polyfill/\"\n          >https://cdnjs.cloudflare.com/polyfill/</a\n        >을 사용할 수 있습니다.\n      </p>\n      <pre><code class=\"language-html\">&lt;script src=&quot;https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt&quot;&gt;&lt;/script&gt;\n</code></pre>\n      <h2 id=\"browser-and-node-versions\">브라우저와 node 버전</h2>\n      <p>\n        SuperAgent에는 두 가지 구현 방식이 있습니다. 하나는 웹 브라우저용(XHR\n        사용)이고, 다른 하나는 Node.JS용(core http 모듈 사용)입니다. 기본적으로\n        Browserify와 WebPack은 브라우저 버전을 선택합니다.\n      </p>\n      <p>\n        Node.JS용 코드를 컴파일하려면 WebPack 설정에서 반드시\n        <a href=\"https://webpack.github.io/../configuration.html#target\"\n          >node target</a\n        >\n        을 지정해야 합니다.\n      </p>\n    </div>\n    <a href=\"http://github.com/ladjs/superagent\"\n      ><img\n        style=\"position: absolute; top: 0; right: 0; border: 0\"\n        src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png\"\n        alt=\"Fork me on GitHub\"\n    /></a>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js\"></script>\n    <script>\n      $('code').each(function () {\n        $(this).html(highlight($(this).text()));\n      });\n\n      function highlight(js) {\n        return js\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n          .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(\n            /\\bnew *(\\w+)/gm,\n            '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>'\n          )\n          .replace(\n            /\\b(function|new|throw|return|var|if|else)\\b/gm,\n            '<span class=\"keyword\">$1</span>'\n          );\n      }\n    </script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js\"></script>\n    <script>\n      // Only use tocbot for main docs, not test docs\n      if (document.querySelector('#superagent')) {\n        tocbot.init({\n          // Where to render the table of contents.\n          tocSelector: '#menu',\n          // Where to grab the headings to build the table of contents.\n          contentSelector: '#content',\n          // Which headings to grab inside of the contentSelector element.\n          headingSelector: 'h2',\n          smoothScroll: false\n        });\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/ko_KR/index.md",
    "content": "# SuperAgent\n\nSuperAgent는 기존의 복잡한 요청 API에 대한 불만에서 출발해 유연성, 가독성, 그리고 낮은 학습 난이도를 목표로 설계된 경량 Ajax API입니다. 또한 Node.js 환경에서도 동작합니다!\n\n```javascript\nrequest\n  .post('/api/pet')\n  .send({ name: 'Manny', species: 'cat' })\n  .set('X-API-Key', 'foobar')\n  .set('Accept', 'application/json')\n  .then((res) => {\n    alert('yay got ' + JSON.stringify(res.body));\n  });\n```\n\n## 테스트 문서\n\n[**English**](/superagent/)\n\n다음의 [테스트 문서](../test.html)는 [Mocha](https://mochajs.org/)의 \"doc\" 리포터를 사용해 생성되었으며, 실제 테스트 스위트를 직접 반영합니다.  \n이 문서는 추가적인 참고 자료로 활용할 수 있습니다.\n\n## 기본 요청\n\n요청은 `request` 객체에서 적절한 메서드를 호출하여 시작되며, 그 다음 `.then()` 또는 `.end()` 혹은 [`await`](#promise-and-generator-support)를 사용해 요청을 전송할 수 있습니다. 예를 들어, 간단한 **GET** 요청은 다음과 같습니다.\n\n```javascript\nrequest\n  .get('/search')\n  .then((res) => {\n    // res.body, res.headers, res.status\n  })\n  .catch((err) => {\n    // err.message, err.response\n  });\n```\n\nHTTP 메서드는 문자열로도 전달할 수 있습니다.\n\n```javascript\nrequest('GET', '/search').then(success, failure);\n```\n\n예전 방식의 콜백도 지원되지만, 권장되지는 않습니다. `.then()` 대신 `.end()`를 호출하여 요청을 전송할 수 있습니다.\n\n```javascript\nrequest('GET', '/search').end(function (err, res) {\n  if (res.ok) {\n  }\n});\n```\n\n절대 URL을 사용할 수 있습니다. 단, 웹 브라우저에서는 서버가 [CORS](#cors)를 구현한 경우에만 절대 URL이 정상적으로 작동합니다.\n\n```javascript\nrequest.get('https://example.com/search').then((res) => {});\n```\n\n**Node** 클라이언트는 [유닉스 도메인 소켓](https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%89%EC%8A%A4_%EB%8F%84%EB%A9%94%EC%9D%B8_%EC%86%8C%EC%BC%93)을 통한 요청을 지원합니다.\n\n```javascript\n// pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n//          Use `%2F` as `/` in SOCKET_PATH\ntry {\n  const res = await request.get(\n    'http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search'\n  );\n  // res.body, res.headers, res.status\n} catch (err) {\n  // err.message, err.response\n}\n```\n\n**DELETE**, **HEAD**, **PATCH**, **POST**, **PUT** 요청도 사용할 수 있으며, 다음 예시에서 메서드 이름만 변경하면 됩니다.\n\n```javascript\nrequest.head('/favicon.ico').then((res) => {});\n```\n\n**DELETE**는 `delete`가 예약어였던 구형 IE와의 호환성을 위해 `.del()` 메서드로도 호출할 수 있습니다.\n\nHTTP 메서드의 기본값은 **GET**이므로, 다음과 같이 작성해도 유효합니다.\n\n```javascript\nrequest('/search', (err, res) => {});\n```\n\n## HTTP/2 사용하기\n\nHTTP/1.x 폴백 없이 HTTP/2 프로토콜만 사용하려면 `.http2()` 메서드를 호출하여 요청을 전송할 수 있습니다.\n\n```javascript\nconst request = require('superagent');\nconst res = await request.get('https://example.com/h2').http2();\n```\n\n## 헤더 필드 설정하기\n\n헤더 필드 설정은 간단합니다. 필드 이름과 값을 `.set()` 메서드에 전달하면 됩니다.\n\n```javascript\nrequest\n  .get('/search')\n  .set('API-Key', 'foobar')\n  .set('Accept', 'application/json')\n  .then(callback);\n```\n\nYou may also pass an object to set several fields in a single call:\n\n여러 개의 헤더 필드를 한 번에 설정하려면 객체를 전달하면 됩니다.\n\n```javascript\nrequest\n  .get('/search')\n  .set({ 'API-Key': 'foobar', Accept: 'application/json' })\n  .then(callback);\n```\n\n## `GET` 요청\n\n`.query()` 메서드는 객체를 인자로 받아 **GET** 요청 시 쿼리 문자열을 자동으로 생성합니다. 예를 들어 다음 코드는 `/search?query=Manny&range=1..5&order=desc` 경로를 생성합니다.\n\n````js\nrequest\n  .get('/search')\n  .query({ query: 'Manny', range: '1..5', order: 'desc' });\n\n\n```javascript\nrequest\n  .get('/search')\n  .query({ query: 'Manny' })\n  .query({ range: '1..5' })\n  .query({ order: 'desc' })\n  .then((res) => {});\n````\n\n또는 하나의 객체로 설정할 수 있습니다.\n\n```javascript\nrequest\n  .get('/search')\n  .query({ query: 'Manny', range: '1..5', order: 'desc' })\n  .then((res) => {});\n```\n\n`.query()` 메서드는 문자열도 받습니다.\n\n```javascript\nrequest\n  .get('/querystring')\n  .query('search=Manny&range=1..5')\n  .then((res) => {});\n```\n\n조인할 수도 있습니다.\n\n```javascript\nrequest\n  .get('/querystring')\n  .query('search=Manny')\n  .query('range=1..5')\n  .then((res) => {});\n```\n\n## `HEAD` 요청하기\n\nHEAD 요청에서도 `.query()` 메서드를 사용할 수 있습니다. 예를 들어 다음 코드는 `/users?email=joe@smith.com` 경로를 생성합니다.\n\n```javascript\nrequest\n  .head('/users')\n  .query({ email: 'joe@smith.com' })\n  .then((res) => {});\n```\n\n## `POST` / `PUT` 요청\n\n전형적인 JSON **POST** 요청은 Content-Type 헤더를 적절히 설정하고,  \n데이터를 JSON 형식으로 전송하는 방식입니다. 예를 들어 다음과 같은 코드가 이에 해당합니다.\n\n```javascript\nrequest\n  .post('/user')\n  .set('Content-Type', 'application/json')\n  .send('{\"name\":\"tj\",\"pet\":\"tobi\"}')\n  .then(callback)\n  .catch(errorCallback);\n```\n\nJSON은 가장 일반적으로 사용되므로 기본값으로 설정되어 있습니다. 다음 예제는 앞선 예제와 동일한 동작을 수행합니다.\n\n```javascript\nrequest\n  .post('/user')\n  .send({ name: 'tj', pet: 'tobi' })\n  .then(callback, errorCallback);\n```\n\n또는 `.send()` 여러 번 호출할 수 있습니다.\n\n```javascript\nrequest\n  .post('/user')\n  .send({ name: 'tj' })\n  .send({ pet: 'tobi' })\n  .then(callback, errorCallback);\n```\n\n기본적으로 문자열을 전송하면 `Content-Type`이 `application/x-www-form-urlencoded`로 자동 설정됩니다.  \n여러 번 `.send()`를 호출하면 각 문자열이 `&`로 연결되어 최종적으로 `name=tj&pet=tobi`와 같은 결과가 생성됩니다.\n\n```javascript\nrequest\n  .post('/user')\n  .send('name=tj')\n  .send('pet=tobi')\n  .then(callback, errorCallback);\n```\n\nSuperAgent는 다양한 형식으로 확장 가능하지만, 기본적으로 \"json\"과 \"form\" 형식을 지원합니다. `application/x-www-form-urlencoded` 형식으로 데이터를 전송하려면 `.type('form')`을 호출하면 됩니다. 기본 형식은 `\"json\"`입니다. 다음 요청은 본문에 `\"name=tj&pet=tobi\"`를 포함하여 **POST**됩니다.\n\n```javascript\nrequest\n  .post('/user')\n  .type('form')\n  .send({ name: 'tj' })\n  .send({ pet: 'tobi' })\n  .then(callback, errorCallback);\n```\n\n[`FormData`](https://developer.mozilla.org/ko/docs/Web/API/FormData/FormData) 객체를 사용하는 것도 지원됩니다. 다음 예제는 `id=\"myForm\"`인 HTML 폼의 내용을 **POST** 방식으로 전송합니다.\n\n```javascript\nrequest\n  .post('/user')\n  .send(new FormData(document.getElementById('myForm')))\n  .then(callback, errorCallback);\n```\n\n## `Content-Type` 설정하기\n\n가장 명확한 해결책은 `.set()` 메서드를 사용하는 것입니다.\n\n```javascript\nrequest.post('/user').set('Content-Type', 'application/json');\n```\n\n간단하게 `.type()` 메서드를 사용할 수 있으며,  \n표준화된 MIME 타입(`type/subtype`)을 직접 지정하거나  \n\"xml\", \"json\", \"png\" 등과 같은 확장자 이름만으로도 설정할 수 있습니다.\n\n```javascript\nrequest.post('/user').type('application/json');\n\nrequest.post('/user').type('json');\n\nrequest.post('/user').type('png');\n```\n\n## 요청 본문 직렬화하기\n\nSuperAgent는 기본적으로 JSON과 폼 데이터를 자동으로 직렬화합니다.  \n또한 다른 콘텐츠 유형에 대해서도 자동 직렬화를 설정할 수 있습니다.\n\n```js\nrequest.serialize['application/xml'] = function (obj) {\n  return 'string generated from obj';\n};\n\n// 'application/xml' Content-type을 가진 모든 요청은\n// 자동으로 직렬화 됩니다.\n```\n\n사용자 정의 형식으로 페이로드를 전송하려면,  \n요청 단위로 `.serialize()` 메서드를 사용해 SuperAgent의 기본 직렬화 방식을 교체할 수 있습니다.\n\n```js\nrequest\n  .post('/user')\n  .send({ foo: 'bar' })\n  .serialize((obj) => {\n    return 'string generated from obj';\n  });\n```\n\n## 요청 재시도하기\n\n`.retry()` 메서드를 사용하면, 일시적인 오류나 불안정한 인터넷 연결로 인해 요청이 실패한 경우 SuperAgent가 자동으로 재시도합니다.\n\n이 메서드는 두 개의 선택적 인자를 받습니다. 재시도 횟수(기본값은 1)와 콜백 함수입니다. 각 재시도 전에 `callback(err, res)`를 호출합니다. 콜백 함수는 요청을 재시도할지 여부를 결정하기 위해 `true` 또는 `false`를 반환할 수 있습니다. 단, 최대 재시도 횟수는 항상 적용됩니다.\n\n```javascript\n     request\n       .get('https://example.com/search')\n       .retry(2) // 혹은\n       .retry(2, callback)\n       .then(finished);\n       .catch(failed);\n```\n\n멱등한 요청인 경우에만 `.retry()` 메서드를 사용하세요. 예를 들어, 동일한 요청이 서버에 여러 번 도달하더라도 중복 구매와 같은 바람직하지 않은 부작용이 발생하지 않아야 합니다.\n\n모든 요청 메서드는 기본적으로 재시도 대상에 포함됩니다. 따라서 POST 요청을 재시도하지 않도록 하려면, 사용자 정의 재시도 콜백을 전달해야 합니다.\n\n기본적으로 다음과 같은 상태 코드는 자동으로 재시도됩니다.\n\n- `408`\n- `413`\n- `429`\n- `500`\n- `502`\n- `503`\n- `504`\n- `521`\n- `522`\n- `524`\n\n기본적으로 다음과 같은 오류 코드가 자동으로 재시도됩니다.\n\n- `'ETIMEDOUT'`\n- `'ECONNRESET'`\n- `'EADDRINUSE'`\n- `'ECONNREFUSED'`\n- `'EPIPE'`\n- `'ENOTFOUND'`\n- `'ENETUNREACH'`\n- `'EAI_AGAIN'`\n\n## Accept 설정하기\n\n`.type()` 메서드와 유사하게, `.accept()` 메서드를 사용하면 `Accept` 헤더를 간편하게 설정할 수 있습니다. 이 메서드는 `request.types`를 참조하며, `type/subtype` 형식의 MIME 타입 전체 이름이나 \"xml\", \"json\", \"png\" 등의 확장자 형태로도 지정할 수 있어 편리합니다.\n\n```javascript\nrequest.get('/user').accept('application/json');\n\nrequest.get('/user').accept('json');\n\nrequest.post('/user').accept('png');\n```\n\n### Facebook과 Accept JSON\n\nFacebook API를 호출할 때는 반드시 요청 헤더에 `Accept: application/json`을 포함해야 합니다. 그렇지 않으면 Facebook은 `Content-Type: text/javascript; charset=UTF-8`으로 응답하게 되며, SuperAgent는 이 형식을 파싱하지 못해 `res.body`가 `undefined`가 됩니다. `req.accept('json')` 또는 `req.set('Accept', 'application/json')`을 사용할 수 있습니다. 자세한 사항은 [issue 1078](https://github.com/ladjs/superagent/issues/1078)에서 확인해보세요.\n\n## 쿼리 문자열\n\n`req.query(obj)`는 쿼리 문자열을 구성하는 데 사용되는 메서드입니다. 예를 들어 **POST** 요청에서 `?format=json&dest=/login`과 같은 쿼리 문자열을 추가할 수 있습니다.\n\n```javascript\nrequest\n  .post('/')\n  .query({ format: 'json' })\n  .query({ dest: '/login' })\n  .send({ post: 'data', here: 'wahoo' })\n  .then(callback);\n```\n\n기본적으로 쿼리 문자열은 특정한 순서로 조립되지 않습니다. ASCII 순으로 정렬된 쿼리 문자열을 사용하려면 `req.sortQuery()`를 호출하면 됩니다. 또한 `req.sortQuery(myComparisonFn)`을 통해 사용자 정의 정렬 비교 함수를 전달할 수도 있습니다. 비교 함수는 두 개의 인자를 받아 음수, 0 또는 양수를 반환해야 합니다.\n\n```js\n// 기본 정렬 방식\nrequest\n  .get('/user')\n  .query('name=Nick')\n  .query('search=Manny')\n  .sortQuery()\n  .then(callback);\n\n// 사용자 정의 정렬 함수\nrequest\n  .get('/user')\n  .query('name=Nick')\n  .query('search=Manny')\n  .sortQuery((a, b) => a.length - b.length)\n  .then(callback);\n```\n\n## TLS 옵션\n\nNode.js에서 SuperAgent는 HTTPS 요청을 구성할 수 있는 다양한 메서드를 지원합니다.\n\n- `.ca()`: 신뢰할 CA 인증서를 설정합니다.\n- `.cert()`: 클라이언트 인증서 체인을 설정합니다.\n- `.key()`: 클라이언트의 개인 키를 설정합니다.\n- `.pfx()`: PKCS12 형식의 PFX 파일을 사용하여 클라이언트의 개인 키와 인증서 체인을 설정합니다.\n- `.disableTLSCerts()`: 만료되었거나 유효하지 않은 TLS 인증서를 거부하지 않도록 설정합니다. 내부적으로 `rejectUnauthorized=true`가 설정되며, 중간자 공격(MITM)에 노출될 수 있으므로 주의가 필요합니다.\n\n더 자세한 내용은 Node.js [https.request 문서](https://nodejs.org/api/https.html#https_https_request_options_callback)에서 확인할 수 있습니다.\n\n```js\nvar key = fs.readFileSync('key.pem'),\n  cert = fs.readFileSync('cert.pem');\n\nrequest.post('/client-auth').key(key).cert(cert).then(callback);\n```\n\n```js\nvar ca = fs.readFileSync('ca.cert.pem');\n\nrequest\n  .post('https://localhost/private-ca-server')\n  .ca(ca)\n  .then((res) => {});\n```\n\n## Parsing response bodies\n\n## 응답 본문 파싱하기\n\nSuperAgent will parse known response-body data for you,\ncurrently supporting `application/x-www-form-urlencoded`,\n`application/json`, and `multipart/form-data`. You can setup\nautomatic parsing for other response-body data as well:\n\nSuperAgent는 응답 본문 데이터를 자동으로 파싱해줍니다.  \n현재 `application/x-www-form-urlencoded`, `application/json`, `multipart/form-data`을 지원합니다. 이외의 응답 본문 데이터에 대해서도 자동 파싱을 설정할 수 있습니다.\n\n```js\n// 브라우저\nrequest.parse['application/xml'] = function (str) {\n  return { object: 'parsed from str' };\n};\n\n// node\nrequest.parse['application/xml'] = function (res, cb) {\n  // 응답 문자를 파싱하고 res.body를 여기서 설정하세요\n\n  cb(null, res);\n};\n\n// 앞으로 'application/xml' 유형의 반응은\n// 자동으로 파싱됩니다\n```\n\n`.buffer(true).parse(fn)` 메서드를 사용하면 내장된 파서보다 우선적으로 적용되는 사용자 정의 파서를 설정할 수 있습니다. `.buffer(false)`로 응답 버퍼링이 비활성화되어 있다면, `response` 이벤트는 본문 파싱이 완료되기 전에 발생하므로 `response.body`를 사용할 수 없습니다.\n\n### JSON / Urlencoded\n\n`res.body` 속성은 파싱된 객체를 나타냅니다. 예를 들어, 응답이 JSON 문자열 `{\"user\":{\"name\":\"tobi\"}}`를 반환했다면, `res.body.user.name`은 \"tobi\" 값을 갖게 됩니다. 마찬가지로 x-www-form-urlencoded 형식의 \"user[name]=tobi\"도 동일한 결과를 제공합니다. 단, 중첩은 한 단계까지만 지원되므로 더 복잡한 구조의 데이터를 다루려면 JSON 형식을 사용하는 것이 좋습니다.\n\n배열은 key를 반복해서 전달하는 방식으로 전송됩니다. 예를 들어, `.send({ color: ['red', 'blue'] })`는 `color=red&color=blue`로 변환되어 전송됩니다. 배열의 key에 `[]`를 포함시키고 싶다면 SuperAgent는 이를 자동으로 처리하지 않으므로, 직접 `color[]`와 같이 key 이름에 대괄호를 추가해야 합니다.\n\n### 다중 파트\n\nNode 클라이언트는 [Formidable](https://github.com/felixge/node-formidable) 모듈을 통해 *multipart/form-data*를 지원합니다.  \n다중 파트 응답을 파싱할 때 `res.files` 객체를 사용할 수 있으며, 이 객체에는 업로드된 파일에 대한 정보가 포함됩니다. 예를 들어, 다음과 같은 multipart 본문을 포함한 응답을 가정해볼 수 있습니다.\n\n    --whoop\n    Content-Disposition: attachment; name=\"image\"; filename=\"tobi.png\"\n    Content-Type: image/png\n\n    ... data here ...\n    --whoop\n    Content-Disposition: form-data; name=\"name\"\n    Content-Type: text/plain\n\n    Tobi\n    --whoop--\n\n`res.body.name`은 \"Tobi\" 값을 가지고 있으며, `res.files.image`는 디스크 경로, 파일 이름 및 기타 속성을 포함한 `File` 객체입니다.\n\n### 바이너리\n\n브라우저에서는 바이너리 응답 본문을 처리하기 위해 `.responseType('blob')`을 사용할 수 있습니다. 이 API는 Node.js 환경에서는 필요하지 않습니다. 이 메서드에서 지원되는 인자 값은 다음과 같습니다.\n\n- `'blob'`는 XMLHttpRequest의 `responseType` 속성에 그대로 전달됩니다.\n- `'arraybuffer'`도 마찬가지로 `responseType` 속성에 전달됩니다.\n\n```js\nreq\n  .get('/binary.data')\n  .responseType('blob')\n  .then((res) => {\n    // 여기서 res.body는 브라우저 기본 Blob 타입입니다.\n  });\n```\n\n더 자세한 내용은 Mozilla Developer Network의 [XMLHttpRequest.responseType 문서](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)에서 확인할 수 있습니다.\n\n## 응답 속성\n\n`Response` 객체에는 응답 텍스트, 파싱된 응답 본문, 헤더 필드, 상태 플래그 등 다양한 유용한 플래그와 속성이 설정되어 있습니다.\n\n### 응답 문자\n\n`res.text` 속성에는 파싱되지 않은 응답 본문 문자열이 포함됩니다. 이 속성은 클라이언트 API에서는 항상 존재하며, Node 환경에서는 MIME 타입이 \"text/_\", \"_/json\", \"x-www-form-urlencoded\"와 일치할 경우에만 기본적으로 제공됩니다. 이러한 제한은 대용량 multipart 파일이나 이미지 등의 본문을 텍스트로 버퍼링하는 것이 매우 비효율적이기 때문에 메모리를 절약하기 위한 목적입니다. 응답을 강제로 버퍼링하려면 \"응답 버퍼링\" 섹션을 참조하세요.\n\n### 응답 본문\n\nSuperAgent는 요청 데이터를 자동으로 직렬화할 뿐만 아니라, 자동으로 파싱할 수도 있습니다. Content-Type에 대해 파서가 정의되어 있는 경우, 해당 타입에 맞게 응답이 파싱되며 기본적으로 \"application/json\"과 \"application/x-www-form-urlencoded\" 형식이 포함됩니다. 파싱된 객체는 `res.body`를 통해 접근할 수 있습니다.\n\n### 응답 헤더 필드\n\n`res.header`는 파싱된 응답 헤더 필드를 담은 객체로, Node.js와 마찬가지로 필드 이름을 소문자로 변환하여 저장합니다.  \n예를 들어, `res.header['content-length']`와 같이 접근할 수 있습니다.\n\n### 응답 콘텐츠 타입\n\nContent-Type 응답 헤더는 특별하게 처리되어 `res.type` 속성은 charset 정보를 제외한 콘텐츠 타입만을 제공합니다. 예를 들어 Content-Type이 \"text/html; charset=utf8\"인 경우, `res.type`은 \"text/html\"을 반환하고, `res.charset` 속성에는 \"utf8\"이 포함됩니다.\n\n### 응답 상태\n\n응답 상태 플래그는 요청이 성공했는지 여부를 비롯한 다양한 유용한 정보를 판단하는 데 도움을 줍니다. 이를 통해 SuperAgent는 RESTful 웹 서비스와 효과적으로 상호작용할 수 있습니다. 현재 정의된 주요 플래그는 다음과 같습니다.\n\n```javascript\nvar type = (status / 100) | 0;\n\n// 상태 / 클래스\nres.status = status;\nres.statusType = type;\n\n// 기본\nres.info = 1 == type;\nres.ok = 2 == type;\nres.clientError = 4 == type;\nres.serverError = 5 == type;\nres.error = 4 == type || 5 == type;\n\n// 편의 기능\nres.accepted = 202 == status;\nres.noContent = 204 == status || 1223 == status;\nres.badRequest = 400 == status;\nres.unauthorized = 401 == status;\nres.notAcceptable = 406 == status;\nres.notFound = 404 == status;\nres.forbidden = 403 == status;\n```\n\n## 요청 중단하기\n\n요청을 중단하려면 `req.abort()` 메서드를 호출하기만 하면 됩니다.\n\n## 타임아웃\n\n때때로 네트워크나 서버가 요청을 수신한 후 응답 없이 멈춰버리는 경우가 있습니다. 이러한 무한 대기를 방지하려면 타임아웃을 설정해야 합니다.\n\n- `req.timeout({deadline: ms})` 또는 `req.timeout(ms)`는 업로드, 리다이렉트, 서버 처리 시간을 포함한 전체 요청이 완료되어야 하는 최종 시간 제한을 설정합니다. `ms`는 0보다 큰 밀리초 단위의 숫자이며, 제한 시간 내에 응답이 완료되지 않으면 요청은 중단됩니다.\n\n- `req.timeout({response: ms})`는 서버로부터 첫 번째 바이트가 도착할 때까지의 최대 대기 시간을 설정합니다. 전체 다운로드 소요 시간은 제한하지 않습니다. 응답 타임아웃은 DNS 조회, TCP/IP 및 TLS 연결, 요청 데이터 업로드 시간을 포함하므로, 서버의 실제 응답 시간보다 몇 초 더 길게 설정하는 것이 좋습니다.\n\n`deadline`과 `response` 타임아웃은 함께 사용하는 것이 좋습니다. 짧은 응답 타임아웃은 응답하지 않는 네트워크를 빠르게 감지하는 데 유용하고, 긴 데드라인은 느리지만 안정적인 네트워크 환경에서 다운로드를 완료할 수 있도록 여유 시간을 제공합니다. 두 타이머 모두 첨부된 파일 업로드에 허용되는 시간을 제한합니다. 파일을 업로드하는 경우에는 충분히 긴 타임아웃을 설정하는 것이 좋습니다.\n\n```javascript\nrequest\n  .get('/big-file?network=slow')\n  .timeout({\n    response: 5000, // 서버가 데이터를 보내기 시작할 때까지 최대 5초간 기다립니다.\n    deadline: 60000 // 파일 전체를 로드하는 데 최대 1분까지 허용합니다.\n  })\n  .then(\n    (res) => {\n      /* 제시간 응답 수신 */\n    },\n    (err) => {\n      if (err.timeout) {\n        /* 시간 초과! */\n      } else {\n        /* 그 외 오류 */\n      }\n    }\n  );\n```\n\n타임아웃 오류에는 `.timeout` 속성이 포함되어 있습니다.\n\n## 인증\n\nNode와 브라우저 환경에서 `.auth()` 메서드를 사용하여 인증을 수행할 수 있습니다.\n\n```javascript\nrequest.get('http://local').auth('tobi', 'learnboost').then(callback);\n```\n\n_Node_ 클라이언트에서는 기본 인증을 URL 내에 \"user:pass\" 형식으로 포함시킬 수 있습니다.\n\n```javascript\nrequest.get('http://tobi:learnboost@local').then(callback);\n```\n\n기본적으로 `Basic` 인증만 사용됩니다. 브라우저에서는 `{type: 'auto'}`를 추가하면 Digest, NTLM 등 브라우저에 내장된 모든 인증 방식을 사용할 수 있습니다.\n\n```javascript\nrequest.auth('digest', 'secret', { type: 'auto' });\n```\n\n`auth` 메서드는 토큰 기반 인증을 위한 `type: 'bearer'` 옵션도 지원합니다.\n\n```javascript\nrequest.auth('my_token', { type: 'bearer' });\n```\n\n## 다음 리다이렉션 따라가기\n\n기본적으로 최대 5번까지 리다이렉션이 자동으로 따라가며, 필요에 따라 `res.redirects(n)` 메서드를 사용하여 이 횟수를 지정할 수 있습니다.\n\n```javascript\nconst response = await request.get('/some.png').redirects(2);\n```\n\n리다이렉션 횟수가 제한을 초과하면 오류로 간주됩니다. 이를 성공적인 응답으로 처리하려면 `.ok(res => res.status < 400)` 메서드를 사용하세요.\n\n## 전역 상태를 위한 에이전트\n\n### 쿠키 저장하기\n\nNode에서 SuperAgent는 기본적으로 쿠키를 저장하지 않습니다. 하지만 `.agent()` 메서드를 사용하면 쿠키를 저장하는 SuperAgent 인스턴스를 생성할 수 있습니다. 각 인스턴스는 독립적인 쿠키 저장소를 가지고 있습니다.\n\n```javascript\nconst agent = request.agent();\nagent.post('/login').then(() => {\n  return agent.get('/cookied-page');\n});\n```\n\n브라우저에서는 쿠키가 자동으로 관리되므로 `.agent()`를 사용해도 쿠키가 분리되지는 않습니다.\n\n### 다중 요청을 위한 기본 옵션\n\n에이전트에서 호출된 일반 요청 메서드는 해당 에이전트가 처리하는 모든 요청에 대해 기본값으로 적용됩니다.\n\n```javascript\nconst agent = request.agent().use(plugin).auth(shared);\n\nawait agent.get('/with-plugin-and-auth');\nawait agent.get('/also-with-plugin-and-auth');\n```\n\n에이전트가 기본 옵션을 설정할 수 있도록 지원하는 메서드 목록입니다. `use`, `on`, `once`, `set`, `query`, `type`, `accept`, `auth`, `withCredentials`, `sortQuery`, `retry`, `ok`, `redirects`, `timeout`, `buffer`, `serialize`, `parse`, `ca`, `key`, `pfx`, `cert`.\n\n## 데이터 전달 방식\n\n`.pipe()`는 `.end()` 또는 `.then()` 메서드 **대신** 사용되며, Node 클라이언트는 요청과 응답 간에 데이터를 주고받도록 파이프 처리할 수 있습니다.\n\n예를 들어, 파일의 콘텐츠를 요청 본문으로 전달하는 경우는 다음과 같습니다.\n\n```javascript\nconst request = require('superagent');\nconst fs = require('fs');\n\nconst stream = fs.createReadStream('path/to/my.json');\nconst req = request.post('/somewhere');\nreq.type('json');\nstream.pipe(req);\n```\n\n요청에 데이터를 파이프할 경우, SuperAgent는 해당 데이터를 [청크 전송 인코딩](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) 방식으로 전송합니다. 이 방식은 Python WSGI 서버 등 모든 서버에서 지원되지는 않습니다.\n\n응답을 파일로 저장하려면 다음과 같이 파이프 처리할 수 있습니다.\n\n```javascript\nconst stream = fs.createWriteStream('path/to/my.json');\nconst req = request.get('/some.json');\nreq.pipe(stream);\n```\n\n파이프와 콜백 또는 프로미스는 **함께 사용할 수 없으며**, `.end()`나 `Response` 객체의 결과를 파이프 처리해서는 안 됩니다.\n\n```javascript\n// 이러한 방식으로 하지 마세요.\nconst stream = getAWritableStream();\nconst req = request\n  .get('/some.json')\n  // 나쁨: 이 방식은 스트림에 올바르지 않은 데이터를 전달하며 예기치 못한 방식으로 실패할 수 있습니다.\n  .end((err, this_does_not_work) => this_does_not_work.pipe(stream));\nconst req = request\n  .get('/some.json')\n  .end()\n  // 나쁨: 이 방식도 지원되지 않으며, .pipe는 자동으로 .end를 호출합니다.\n  .pipe(nope_its_too_late);\n```\n\nSuperAgent의 [향후 버전](https://github.com/ladjs/superagent/issues/1188)에서는 `pipe()`를 부적절하게 호출하면 실패하게 됩니다.\n\n## 다중 부분 요청\n\n`.attach()`와 `.field()` 메서드를 제공하는 SuperAgent는 다중 부분 요청을 구성하는 데에도 매우 유용합니다.\n\n`.field()` 또는 `.attach()`를 사용할 경우 `.send()`는 사용할 수 없으며, `Content-Type` 헤더를 직접 설정해서는 안 됩니다. 올바른 타입은 자동으로 지정됩니다.\n\n### 파일 첨부하기\n\n`.attach(name, [file], [options])`를 사용하여 파일을 전송할 수 있습니다. 여러 파일을 첨부하려면 `.attach`를 반복 호출하면 됩니다. 인자는 다음과 같습니다.\n\n- `name` — 폼 이름 필드\n- `file` — 파일 경로의 문자열 또는 `Blob`/`Buffer` 객체.\n- `options` — (선택) 사용자 정의 파일 이름의 문자열 또는 `{filename: string}` 형식의 객체. Node 환경에서는 `{contentType: 'mime/type'}`도 지원하며 브라우저에서는 적절한 타입의 `Blob` 객체를 생성해야 합니다.\n\n<br>\n\n```javascript\nrequest\n  .post('/upload')\n  .attach('image1', 'path/to/felix.jpeg')\n  .attach('image2', imageBuffer, 'luna.jpeg')\n  .field('caption', 'My cats')\n  .then(callback);\n```\n\n### 필드 값\n\n`.field(name, value)` 및 `.field({name: value})`를 사용해 HTML 폼 필드처럼 값을 설정할 수 있습니다. 예를 들어 이름과 이메일 정보를 함께 여러 이미지를 업로드하려면, 요청은 다음과 같이 구성될 수 있습니다.\n\n```javascript\nrequest\n  .post('/upload')\n  .field('user[name]', 'Tobi')\n  .field('user[email]', 'tobi@learnboost.com')\n  .field('friends[]', ['loki', 'jane'])\n  .attach('image', 'path/to/tobi.png')\n  .then(callback);\n```\n\n## 압축\n\nnode 클라이언트는 압축된 응답을 지원하며, 아무 것도 하지 않아도 됩니다! 그냥 작동합니다.\n\n## 응답 버퍼링\n\nTo force buffering of response bodies as `res.text` you may invoke `req.buffer()`. To undo the default of buffering for text responses such as \"text/plain\", \"text/html\" etc you may invoke `req.buffer(false)`.\n\n`.req.buffer()`를 호출하면 응답 본문을 `res.text`로 강제 버퍼링할 수 있습니다. \"text/plain\", \"text/html\" 등 텍스트 응답의 기본 버퍼링을 취소하려면 `.req.buffer(false)`를 호출하세요.\n\n`res.buffered` 플래그가 제공되면, 이를 활용하여 동일한 콜백 함수에서 버퍼링된 응답과 버퍼링되지 않은 응답을 모두 처리할 수 있습니다.\n\n## CORS\n\n보안상의 이유로 브라우저는 서버가 CORS 헤더를 통해 명시적으로 허용하지 않으면 교차 출처 요청(cross-origin requests)을 차단합니다. 브라우저는 또한 서버가 어떤 HTTP 헤더와 메서드를 허용하는지 확인하기 위해 추가적인 **OPTIONS** 요청을 전송합니다. [CORS에 대해 더 알아보기](https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CORS).\n\n`.withCredentials()` 메서드는 origin(출처)에서 쿠키를 전송할 수 있도록 활성화합니다. 단, 이 기능은 `Access-Control-Allow-Origin` 값이 와일드카드(\"\\*\")가 _아니어야_ 하며, `Access-Control-Allow-Credentials` 값이 `\"true\"`일 경우에만 작동합니다.\n\n```javascript\nrequest\n  .get('https://api.example.com:4001/')\n  .withCredentials()\n  .then((res) => {\n    assert.equal(200, res.status);\n    assert.equal('tobi', res.text);\n  });\n```\n\n## 오류 처리하기\n\n콜백 함수는 항상 두 개의 인자를 전달합니다. 오류와 응답입니다. 오류가 발생하지 않으면, 첫 번째 인자는 null 입니다.\n\n```javascript\nrequest\n  .post('/upload')\n  .attach('image', 'path/to/tobi.png')\n  .then((res) => {});\n```\n\n\"error\" 이벤트도 발생하며, 이를 통해 오류를 감지하고 처리할 수 있습니다.\n\n```javascript\nrequest\n  .post('/upload')\n  .attach('image', 'path/to/tobi.png')\n  .on('error', handle)\n  .then((res) => {});\n```\n\n**SuperAgent는 기본적으로 4xx 및 5xx 응답(그리고 처리되지 않은 3xx 응답도 포함)을 오류**로 간주합니다. 예를 들어 `304 Not Modified`, `403 Forbidden`, `500 Internal Server Error` 같은 응답을 받으면 해당 상태 정보는 `err.status`를 통해 확인할 수 있습니다. 이러한 응답으로부터 발생한 오류에는 \"[응답 요소](#response-properties)\"에서 언급한 모든 속성을 포함한 `err.response` 필드도 포함됩니다. 이 라이브러리는 일반적으로 성공 응답만을 원하고, HTTP 오류 상태 코드를 오류로 처리하는 경우를 대비하여 이러한 방식으로 동작합니다. 하지만 특정 오류 조건에 대해서는 사용자 정의 로직을 허용하도록 설계되어 있습니다.\n\n네트워크 실패, 시간초과, 응답 없는 오류는 `err.status` 또는 `err.response` 필드를 포함하지 않습니다.\n\n404 또는 HTTP 오류 응답을 처리하고 싶다면, `error.status` 요소를 사용할 수 있습니다. HTTP 오류(4xx 또는 5xx 응답)가 발생했을 때 `res.error` 요소는 `Error` 객체이고 이는 다음과 같이 에러 확인을 수행할 수 있습니다.\n\n```javascript\nif (err && err.status === 404) {\n  alert('oh no ' + res.body.message);\n} else if (err) {\n  // 그 외 다른 모든 오류 유형은 일반적으로 처리합니다\n}\n```\n\n대안으로, `.ok(callback)` 메서드를 사용하여 응답이 오류인지 아닌지 결정할 수 있습니다. `ok` 콜백은 응답을 받고 응답이 성공으로 해석되면 `true`를 반환합니다.\n\n```javascript\nrequest\n  .get('/404')\n  .ok((res) => res.status < 500)\n  .then((response) => {\n    // 404 페이지를 성공적인 응답으로 처리합니다\n  });\n```\n\n## 진행과정 추적하기\n\nSuperAgent는 업로드와 큰 파일 다운로드에서 `progress` 이벤트를 동작시킵니다.\n\n```javascript\nrequest\n  .post(url)\n  .attach('field_name', file)\n  .on('progress', (event) => {\n    /* 이벤트 객체는 다음과 같습니다.\n        {\n          direction: \"upload\" or \"download\"\n          percent: 0 to 100 // 0에서 100까지 (파일 크기를 알 수 없는 경우 생략될 수 있습니다)\n          total: // 전체 파일 크기 (생략될 수 있습니다)\n          loaded: // 현재까지 다운로드되거나 업로드된 바이트 수\n        } */\n  })\n  .then();\n```\n\n## 로컬 호스트에서 테스트하기\n\n### 특정 IP 주소 연결 설정하기\n\nIn Node.js it's possible to ignore DNS resolution and direct all requests to a specific IP address using `.connect()` method. For example, this request will go to localhost instead of `example.com`:\n\nNode.js에서는 DNS를 무시하고 `.connect()` 메서드를 사용하여 모든 요청을 특정 IP 주소로 직접 연결할 수 있습니다. 예를 들어, 이 요청은 `example.com` 대신 로컬호스트로 전달됩니다.\n\n```javascript\nconst res = await request.get('http://example.com').connect('127.0.0.1');\n```\n\n요청은 리다이렉트 되어, 여러 호스트명과 IP를 특정지을 수 있으며 특별한 `*`를 대체로 설정할 수 있습니다. (다른 와일드 카드는 지원되지 않습니다). 요청은 원본 값을 가지며 본인의 `Host` 헤더를 유지합니다. `.connect(undefined)`는 이러한 기능을 끕니다.\n\n```javascript\nconst res = await request.get('http://redir.example.com:555').connect({\n  'redir.example.com': '127.0.0.1', // redir.example.com:555는 127.0.0.1:555를 사용합니다.\n  'www.example.com': false, // 이 항목은 재정의하지 마세요. 일반적인 DNS 설정을 사용합니다.\n  'mapped.example.com': { host: '127.0.0.1', port: 8080 }, // mapped.example.com의 모든 포트는 127.0.0.1:8080으로 매핑됩니다.\n  '*': 'proxy.example.com' // 나머지 모든 요청은 이 호스트로 전달됩니다\n});\n```\n\n### 로컬 호스트에서 깨지거나 보안되지 않은 HTTPS 무시하기\n\nNode.js에서 HTTPS 설정이 잘못되었거나 보안성이 떨어지는 경우(예: 자체 서명된 인증서를 사용하면서 `.ca()`를 지정하지 않은 경우), `.trustLocalhost()`를 호출하면 `localhost`로의 요청을 허용할 수 있습니다.\n\n```javascript\nconst res = await request.get('https://localhost').trustLocalhost();\n```\n\n`.connect(\"127.0.0.1\")`와 함께 사용하면 HTTPS 요청을 어떤 도메인에서든 `localhost`로 강제로 리다이렉트할 수 있습니다.\n\n`localhost`는 신뢰되지 않은 네트워크에 노출되지 않는 루프백 인터페이스이기 때문에, 깨진 HTTPS를 무시하는 것이 일반적으로 안전합니다. `localhost`를 신뢰하도록 설정하는 것이 향후 기본값이 될 수 있습니다. `127.0.0.1`의 진위 여부를 강제로 검사하려면 `.trustLocalhost(false)`를 사용하세요.\n\n다른 IP 주소로 요청을 보낼 때 HTTPS 보안을 비활성화하는 기능은 의도적으로 지원하지 않습니다. 이러한 옵션은 HTTPS 문제를 빠르게 \"해결\"하려는 방식으로 오용되는 경우가 많기 때문입니다. [Let's Encrypt](https://certbot.eff.org)를 통해 무료 HTTPS 인증서를 발급받거나, `.ca(ca_public_pem)`을 사용해 자체 서명된 인증서를 신뢰할 수 있도록 직접 CA를 설정할 수 있습니다.\n\n## Promise 및 Generator 지원\n\nSuperAgent의 요청은 \"thenable\" 객체이며, JavaScript의 Promise 및 `async`/`await` 문법과 호환됩니다.\n\n```javascript\nconst res = await request.get(url);\n```\n\nPromise를 사용할 경우, **`.end()` 또는 `.pipe()`를 호출하지 마세요**. `.then()` 또는 `await`를 사용하면 요청을 처리할 수 있는 다른 방식들이 모두 비활성화됩니다.\n\n[co](https://github.com/tj/co)와 같은 라이브러리나 [koa](https://github.com/koajs/koa)와 같은 웹 프레임워크에서는 SuperAgent의 모든 메서드에서 `yield`를 사용할 수 있습니다.\n\n```javascript\n    const req = request\n      .get('http://local')\n      .auth('tobi', 'learnboost');\n    const res = yield req;\n```\n\nSuperAgent는 전역 `Promise` 객체가 존재하는 환경에서 동작하도록 설계되어 있습니다. Internet Explorer나 Node.js 0.10에서 promise를 사용하려면 v7 버전과 폴리필이 필요합니다.\n\nv8 버전부터는 IE에 대한 지원이 중단되었습니다. Opera 85나 iOS Safari 12.2–12.5 등을 지원하려면 WeakRef와 BigInt에 대한 폴리필을 추가해야 합니다. 예를 들어 <https://cdnjs.cloudflare.com/polyfill/>을 사용할 수 있습니다.\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt\"></script>\n```\n\n## 브라우저와 node 버전\n\nSuperAgent에는 두 가지 구현 방식이 있습니다. 하나는 웹 브라우저용(XHR 사용)이고, 다른 하나는 Node.JS용(core http 모듈 사용)입니다. 기본적으로 Browserify와 WebPack은 브라우저 버전을 선택합니다.\n\nNode.JS용 코드를 컴파일하려면 WebPack 설정에서 반드시 [node target](https://webpack.github.io/docs/configuration.html#target)을 지정해야 합니다.\n"
  },
  {
    "path": "docs/style.css",
    "content": "body {\n  padding: 40px 80px;\n  font: 14px/1.5 \"Helvetica Neue\", Helvetica, sans-serif;\n  background: #181818 url(images/bg.png);\n  text-align: center;\n}\n\n#content {\n  margin: 0 auto;\n  padding: 10px 40px;\n  text-align: left;\n  background: white;\n  width: 50%;\n  -webkit-border-radius: 2px;\n  -moz-border-radius: 2px;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 2px 5px 0 black;\n}\n\n#menu {\n  font-size: 13px;\n  margin: 0;\n  padding: 0;\n  text-align: left;\n  position: fixed;\n  top: 15px;\n  left: 15px;\n}\n\n#menu ul {\n  margin: 0;\n  padding: 0;\n}\n\n#menu li {\n  list-style: none;\n}\n\n#menu a {\n  color: rgba(255,255,255,.5);\n  text-decoration: none;\n}\n\n#menu a:hover {\n  color: white;\n}\n\n#menu .active a {\n  color: white;\n}\n\npre {\n  padding: 10px;\n}\n\ncode {\n  font-family: monaco, monospace, sans-serif;\n  font-size: 0.85em;\n}\n\np code {\n  border: 1px solid #ECEA75;\n  padding: 1px 3px;\n  -webkit-border-radius: 2px;\n  -moz-border-radius: 2px;\n  border-radius: 2px;\n  background: #FDFCD1;\n}\n\npre {\n  padding: 20px 25px;\n  border: 1px solid #ddd;\n  -webkit-box-shadow: inset 0 0 5px #eee;\n  -moz-box-shadow: inset 0 0 5px #eee;\n  box-shadow: inset 0 0 5px #eee;\n  overflow: scroll;\n}\n\ncode .comment { color: #ddd }\ncode .init { color: #2F6FAD }\ncode .string { color: #5890AD }\ncode .keyword { color: #8A6343 }\ncode .number { color: #2F6FAD }\n\n/* override tocbot style to avoid vertical white line in table of content */\n.toc-link::before {\n  content: initial;\n}\n"
  },
  {
    "path": "docs/tail.html",
    "content": "    </div>\n    <a href=\"http://github.com/ladjs/superagent\"><img style=\"position: absolute; top: 0; right: 0; border: 0;\" src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png\" alt=\"Fork me on GitHub\"></a>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js\"></script>\n    <script>\n      $('code').each(function(){\n        $(this).html(highlight($(this).text()));\n      });\n\n      function highlight(js) {\n        return js\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n          .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n          .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n      }\n    </script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js\"></script>\n    <script>\n      // Only use tocbot for main docs, not test docs\n      if (document.querySelector('#superagent')) {\n        tocbot.init({\n          // Where to render the table of contents.\n          tocSelector: '#menu',\n          // Where to grab the headings to build the table of contents.\n          contentSelector: '#content',\n          // Which headings to grab inside of the contentSelector element.\n          headingSelector: 'h2',\n          smoothScroll: false\n        });\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/test.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css\">\n    <link rel=\"stylesheet\" href=\"docs/style.css\">\n  </head>\n  <body>\n    <ul id=\"menu\"></ul>\n    <div id=\"content\">\ntest on node with http1\ntest on plain node\n    <section class=\"suite\">\n      <h1>Agent</h1>\n      <dl>\n        <dt>should remember defaults</dt>\n        <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nlet called = 0;\nlet event_called = 0;\nconst agent = request\n  .agent()\n  .accept(&#x27;json&#x27;)\n  .use(() =&#x3E; {\n    called++;\n  })\n  .once(&#x27;request&#x27;, () =&#x3E; {\n    event_called++;\n  })\n  .query({ hello: &#x27;world&#x27; })\n  .set(&#x27;X-test&#x27;, &#x27;testing&#x27;);\nassert.equal(0, called);\nassert.equal(0, event_called);\nreturn agent\n  .get(&#x60;${base}/echo&#x60;)\n  .then((res) =&#x3E; {\n    assert.equal(1, called);\n    assert.equal(1, event_called);\n    assert.equal(&#x27;application/json&#x27;, res.headers.accept);\n    assert.equal(&#x27;testing&#x27;, res.headers[&#x27;x-test&#x27;]);\n    return agent.get(&#x60;${base}/querystring&#x60;);\n  })\n  .then((res) =&#x3E; {\n    assert.equal(2, called);\n    assert.equal(2, event_called);\n    assert.deepEqual({ hello: &#x27;world&#x27; }, res.body);\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>res.statusCode</h1>\n          <dl>\n            <dt>should set statusCode</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.strictEqual(res.statusCode, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>should allow the send shorthand</h1>\n          <dl>\n            <dt>with callback in the method call</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  assert.equal(res.status, 200);\n  done();\n});</code></pre></dd>\n            <dt>with data in the method call</dt>\n            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }).end((error, res) =&#x3E; {\n  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);\n  done();\n});</code></pre></dd>\n            <dt>with callback and data in the method call</dt>\n            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }, (error, res) =&#x3E; {\n  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with a callback</h1>\n          <dl>\n            <dt>should invoke .end()</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(res.status, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.end()</h1>\n          <dl>\n            <dt>should issue a request</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(res.status, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n            <dt>is optional with a promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/login&#x60;)\n  .then((res) =&#x3E; res.status)\n  .then()\n  .then((status) =&#x3E; {\n    assert.equal(200, status, &#x27;Real promises pass results through&#x27;);\n  });</code></pre></dd>\n            <dt>called only once with a promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nconst request_ = request.get(&#x60;${uri}/unique&#x60;);\nreturn Promise.all([request_, request_, request_]).then((results) =&#x3E; {\n  for (const item of results) {\n    assert.deepEqual(\n      item.body,\n      results[0].body,\n      &#x27;It should keep returning the same result after being called once&#x27;\n    );\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.error</h1>\n          <dl>\n            <dt>ok</dt>\n            <dd><pre><code>let calledErrorEvent = false;\nlet calledOKHandler = false;\nrequest\n  .get(&#x60;${uri}/error&#x60;)\n  .ok((res) =&#x3E; {\n    assert.strictEqual(500, res.status);\n    calledOKHandler = true;\n    return true;\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    calledErrorEvent = true;\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.strictEqual(res.status, 500);\n      assert(!calledErrorEvent);\n      assert(calledOKHandler);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should be an Error object</dt>\n            <dd><pre><code>let calledErrorEvent = false;\nrequest\n  .get(&#x60;${uri}/error&#x60;)\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    assert.strictEqual(error.status, 500);\n    calledErrorEvent = true;\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      if (NODE) {\n        res.error.message.should.equal(&#x27;cannot GET /error (500)&#x27;);\n      } else {\n        res.error.message.should.equal(&#x60;cannot GET ${uri}/error (500)&#x60;);\n      }\n      assert.strictEqual(res.error.status, 500);\n      assert(error, &#x27;should have an error for 500&#x27;);\n      assert.equal(error.message, &#x27;Internal Server Error&#x27;);\n      assert(calledErrorEvent);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>with .then() promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request.get(&#x60;${uri}/error&#x60;).then(\n  () =&#x3E; {\n    assert.fail();\n  },\n  (err) =&#x3E; {\n    assert.equal(err.message, &#x27;Internal Server Error&#x27;);\n  }\n);</code></pre></dd>\n            <dt>with .ok() returning false</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; false)\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;OK&#x27;);\n    }\n  );</code></pre></dd>\n            <dt>with .ok() throwing an Error</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; {\n    throw new Error(&#x27;boom&#x27;);\n  })\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(200, err.status);\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;boom&#x27;);\n    }\n  );</code></pre></dd>\n            <dt>with .ok() throwing an Error with status</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; {\n    const err = new Error(&#x27;boom&#x27;);\n    err.status = 404;\n    throw err;\n  })\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(404, err.status);\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;boom&#x27;);\n    }\n  );</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.header</h1>\n          <dl>\n            <dt>should be an object</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>set headers</h1>\n          <dl>\n            <dt>should only set headers for ownProperties of header</dt>\n            <dd><pre><code>try {\n  request\n    .get(&#x60;${uri}/echo-headers&#x60;)\n    .set(&#x27;valid&#x27;, &#x27;ok&#x27;)\n    .end((error, res) =&#x3E; {\n      if (\n        !error &#x26;&#x26;\n        res.body &#x26;&#x26;\n        res.body.valid &#x26;&#x26;\n        !res.body.hasOwnProperty(&#x27;invalid&#x27;)\n      ) {\n        return done();\n      }\n      done(error || new Error(&#x27;fail&#x27;));\n    });\n} catch (err) {\n  done(err);\n}</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.charset</h1>\n          <dl>\n            <dt>should be set when present</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    res.charset.should.equal(&#x27;utf-8&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.statusType</h1>\n          <dl>\n            <dt>should provide the first digit</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(!error, &#x27;should not have an error for success responses&#x27;);\n    assert.equal(200, res.status);\n    assert.equal(2, res.statusType);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.type</h1>\n          <dl>\n            <dt>should provide the mime-type void of params</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    res.type.should.equal(&#x27;text/html&#x27;);\n    res.charset.should.equal(&#x27;utf-8&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.set(field, val)</h1>\n          <dl>\n            <dt>should set the header field</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;X-Bar&#x27;, &#x27;baz&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);\n      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.set(obj)</h1>\n          <dl>\n            <dt>should set the header fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set({ &#x27;X-Foo&#x27;: &#x27;bar&#x27;, &#x27;X-Bar&#x27;: &#x27;baz&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);\n      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.type(str)</h1>\n          <dl>\n            <dt>should set the Content-Type</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;text/x-foo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/x-foo&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;json&#x22;</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;{&#x22;a&#x22;: 1}&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;html&#x22;</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;html&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/html&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.accept(str)</h1>\n          <dl>\n            <dt>should set Accept</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;text/x-foo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;text/x-foo&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;json&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;application/json&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;xml&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      // Mime module keeps changing this :(\n      assert(\n        res.header.accept == &#x27;application/xml&#x27; ||\n          res.header.accept == &#x27;text/xml&#x27;\n      );\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;html&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;html&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;text/html&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.send(str)</h1>\n          <dl>\n            <dt>should write the string</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.send(Object)</h1>\n          <dl>\n            <dt>should default to json</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when called several times</h1>\n              <dl>\n                <dt>should merge the objects</dt>\n                <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .send({ age: 1 })\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      if (NODE) {\n        res.buffered.should.be.true();\n      }\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.end(fn)</h1>\n          <dl>\n            <dt>should check arity</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should emit request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;);\nrequest_.on(&#x27;request&#x27;, (request) =&#x3E; {\n  assert.equal(request_, request);\n  done();\n});\nrequest_.end();</code></pre></dd>\n            <dt>should emit response</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .on(&#x27;response&#x27;, (res) =&#x3E; {\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.then(fulfill, reject)</h1>\n          <dl>\n            <dt>should support successful fulfills with .then(fulfill)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .then((res) =&#x3E; {\n    res.type.should.equal(&#x27;application/json&#x27;);\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should reject an error with .then(null, reject)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest.get(&#x60;${uri}/error&#x60;).then(null, (err) =&#x3E; {\n  assert.equal(err.status, 500);\n  assert.equal(err.response.text, &#x27;boom&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.catch(reject)</h1>\n          <dl>\n            <dt>should reject an error with .catch(reject)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest.get(&#x60;${uri}/error&#x60;).catch((err) =&#x3E; {\n  assert.equal(err.status, 500);\n  assert.equal(err.response.text, &#x27;boom&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.abort()</h1>\n          <dl>\n            <dt>should abort the request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\nrequest_.on(&#x27;error&#x27;, (error) =&#x3E; {\n  done(error);\n});\nrequest_.on(&#x27;abort&#x27;, done);\nsetTimeout(() =&#x3E; {\n  request_.abort();\n}, 500);</code></pre></dd>\n            <dt>should abort the promise</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nsetTimeout(() =&#x3E; {\n  request_.abort();\n}, 10);\nreturn request_.then(\n  () =&#x3E; {\n    assert.fail(&#x27;should not complete the request&#x27;);\n  },\n  (err) =&#x3E; {\n    assert.equal(&#x27;ABORTED&#x27;, err.code);\n  }\n);</code></pre></dd>\n            <dt>should allow chaining .abort() several times</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\n// This also verifies only a single &#x27;done&#x27; event is emitted\nrequest_.on(&#x27;abort&#x27;, done);\nsetTimeout(() =&#x3E; {\n  request_.abort().abort().abort();\n}, 1000);</code></pre></dd>\n            <dt>should not allow abort then end</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/delay/3000&#x60;)\n  .abort()\n  .end((error, res) =&#x3E; {\n    done(error ? undefined : new Error(&#x27;Expected abort error&#x27;));\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.toJSON()</h1>\n          <dl>\n            <dt>should describe the request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;).send({ foo: &#x27;baz&#x27; });\nrequest_.end((error, res) =&#x3E; {\n  try {\n    const json = request_.toJSON();\n    assert.equal(&#x27;POST&#x27;, json.method);\n    assert(/\\/echo$/.test(json.url));\n    assert.equal(&#x27;baz&#x27;, json.data.foo);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.options()</h1>\n          <dl>\n            <dt>should allow request body</dt>\n            <dd><pre><code>request\n  .options(&#x60;${uri}/options/echo/body&#x60;)\n  .send({ foo: &#x27;baz&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(error, null);\n      assert.strictEqual(res.body.foo, &#x27;baz&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.sortQuery()</h1>\n          <dl>\n            <dt>nop with no querystring</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .sortQuery()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should sort the request querystring</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?order=desc&#x26;search=Manny&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should allow disabling sorting</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery() // take default of true\n  .sortQuery(false) // override it in later call\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?search=Manny&#x26;order=desc&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should sort the request querystring using customized function</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;name=Nick&#x27;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery((a, b) =&#x3E; a.length - b.length)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?name=Nick&#x26;order=desc&#x26;search=Manny&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.set(&#x22;Content-Type&#x22;, contentType)</h1>\n      <dl>\n        <dt>should work with just the contentType component</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error) =&#x3E; {\n    assert(!error);\n    done();\n  });</code></pre></dd>\n        <dt>should work with the charset component</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json; charset=utf-8&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error) =&#x3E; {\n    assert(!error);\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(Object) as &#x22;form&#x22;</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>with req.type() set to form</h1>\n          <dl>\n            <dt>should send x-www-form-urlencoded data</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;form&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.text.should.equal(&#x27;name=tobi&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>when called several times</h1>\n          <dl>\n            <dt>should merge the objects</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;form&#x27;)\n  .send({ name: { first: &#x27;tobi&#x27;, last: &#x27;holowaychuk&#x27; } })\n  .send({ age: &#x27;1&#x27; })\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.text.should.equal(\n      &#x27;name%5Bfirst%5D=tobi&#x26;name%5Blast%5D=holowaychuk&#x26;age=1&#x27;\n    );\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.attach</h1>\n      <dl>\n        <dt>ignores null file</dt>\n        <dd><pre><code>request\n  .post(&#x27;/echo&#x27;)\n  .attach(&#x27;image&#x27;, null)\n  .end((error, res) =&#x3E; {\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.field</h1>\n      <dl>\n        <dt>allow bools</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field(&#x27;bools&#x27;, true)\n  .field(&#x27;strings&#x27;, &#x27;true&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>allow objects</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field({ bools: true, strings: &#x27;true&#x27; })\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>works with arrays in objects</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field({ numbers: [1, 2, 3] })\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { numbers: [&#x27;1&#x27;, &#x27;2&#x27;, &#x27;3&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>works with arrays</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field(&#x27;letters&#x27;, [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;])\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { letters: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>throw when empty</dt>\n        <dd><pre><code>should.throws(() =&#x3E; {\n  request.post(&#x60;${base}/echo&#x60;).field();\n}, /name/);\nshould.throws(() =&#x3E; {\n  request.post(&#x60;${base}/echo&#x60;).field(&#x27;name&#x27;);\n}, /val/);</code></pre></dd>\n        <dt>cannot be mixed with send()</dt>\n        <dd><pre><code>assert.throws(() =&#x3E; {\n  request.post(&#x27;/echo&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;).send(&#x27;hi&#x27;);\n});\nassert.throws(() =&#x3E; {\n  request.post(&#x27;/echo&#x27;).send(&#x27;hi&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;);\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(Object) as &#x22;json&#x22;</h1>\n      <dl>\n        <dt>should default to json</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with arrays</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send([1, 2, 3])\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;[1,2,3]&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with value null</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;null&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    assert.strictEqual(res.body, null);\n    done();\n  });</code></pre></dd>\n        <dt>should work with value false</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;false&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.body.should.equal(false);\n    done();\n  });</code></pre></dd>\n        <dt>should work with empty string value</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;&#x22;&#x22;&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.body.should.equal(&#x27;&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with vendor MIME type</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/vnd.example+json&#x27;)\n  .send({ name: &#x27;vendor&#x27; })\n  .end((error, res) =&#x3E; {\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;vendor&#x22;}&#x27;);\n    ({ name: &#x27;vendor&#x27; }.should.eql(res.body));\n    done();\n  });</code></pre></dd>\n        <section class=\"suite\">\n          <h1>when called several times</h1>\n          <dl>\n            <dt>should merge the objects</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .send({ age: 1 })\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);\n    ({ name: &#x27;tobi&#x27;, age: 1 }.should.eql(res.body));\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>application/json</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/json&#x60;).end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;manny&#x22;}&#x27;);\n  res.body.should.eql({ name: &#x27;manny&#x27; });\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>Invalid JSON response</h1>\n          <dl>\n            <dt>should return the raw response</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/invalid-json&#x60;).end((error, res) =&#x3E; {\n  assert.deepEqual(\n    error.rawResponse,\n    &#x22;)]}&#x27;, {&#x27;header&#x27;:{&#x27;code&#x27;:200,&#x27;text&#x27;:&#x27;OK&#x27;,&#x27;version&#x27;:&#x27;1.0&#x27;},&#x27;data&#x27;:&#x27;some data&#x27;}&#x22;\n  );\n  done();\n});</code></pre></dd>\n            <dt>should return the http status code</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/invalid-json-forbidden&#x60;).end((error, res) =&#x3E; {\n  assert.equal(error.statusCode, 403);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on redirect</h1>\n          <dl>\n            <dt>should retain header fields</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/header&#x60;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should preserve timeout across redirects</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/movies/random&#x60;)\n  .timeout(250)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error instanceof Error, &#x27;expected an error&#x27;);\n      error.should.have.property(&#x27;timeout&#x27;, 250);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should successfully redirect after retry on error</dt>\n            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();\nrequest\n  .get(&#x60;${base}/error/redirect/${id}&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(res.text, &#x27;first movie page&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should preserve retries across redirects</dt>\n            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();\nrequest\n  .get(&#x60;${base}/error/redirect-error${id}&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n    assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>request\n  .put(&#x60;${base}/redirect-303&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=get&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>if (isMSIE) return done(); // IE9 broken\nrequest\n  .put(&#x60;${base}/redirect-307&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=put&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>if (isMSIE) return done(); // IE9 broken\nrequest\n  .put(&#x60;${base}/redirect-308&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=put&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <dt>Request inheritance</dt>\n        <dd><pre><code>assert(request.get(&#x60;${uri}/&#x60;) instanceof request.Request);</code></pre></dd>\n        <dt>request() simple GET without callback</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x27;test/test.request.js&#x27;).end();\nnext();</code></pre></dd>\n        <dt>request() simple GET</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(res.text, &#x27;res.text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() simple HEAD</dt>\n        <dd><pre><code>request.head(&#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(!res.text, &#x27;res.text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 5xx</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/error&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(error.message, &#x27;Internal Server Error&#x27;);\n    assert(!res.ok, &#x27;response should not be ok&#x27;);\n    assert(res.error, &#x27;response should be an error&#x27;);\n    assert(!res.clientError, &#x27;response should not be a client error&#x27;);\n    assert(res.serverError, &#x27;response should be a server error&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 4xx</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(error.message, &#x27;Not Found&#x27;);\n    assert(!res.ok, &#x27;response should not be ok&#x27;);\n    assert(res.error, &#x27;response should be an error&#x27;);\n    assert(res.clientError, &#x27;response should be a client error&#x27;);\n    assert(!res.serverError, &#x27;response should not be a server error&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 404 Not Found</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.notFound, &#x27;response should be .notFound&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 400 Bad Request</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/bad-request&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.badRequest, &#x27;response should be .badRequest&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 401 Bad Request</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/unauthorized&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.unauthorized, &#x27;response should be .unauthorized&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 406 Not Acceptable</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/not-acceptable&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.notAcceptable, &#x27;response should be .notAcceptable&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 204 No Content</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.ifError(error);\n    assert(res.noContent, &#x27;response should be .noContent&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() DELETE 204 No Content</dt>\n        <dd><pre><code>request(&#x27;DELETE&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.ifError(error);\n    assert(res.noContent, &#x27;response should be .noContent&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() header parsing</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(&#x27;text/html; charset=utf-8&#x27;, res.header[&#x27;content-type&#x27;]);\n    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() .status</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(404, res.status, &#x27;response .status&#x27;);\n    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>get()</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(404, res.status, &#x27;response .status&#x27;);\n    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>put()</dt>\n        <dd><pre><code>request.put(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;updated&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>put().send()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/user/13/body&#x60;)\n  .send({ user: &#x27;new&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;received new&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>post()</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;created&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>del()</dt>\n        <dd><pre><code>request.del(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>delete()</dt>\n        <dd><pre><code>request.delete(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>post() data</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/todo/item&#x60;)\n  .type(&#x27;application/octet-stream&#x27;)\n  .send(&#x27;tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .type()</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/user/12/pet&#x60;)\n  .type(&#x27;urlencoded&#x27;)\n  .send(&#x27;pet=tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .type() with alias</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/user/12/pet&#x60;)\n  .type(&#x27;application/x-www-form-urlencoded&#x27;)\n  .send(&#x27;pet=tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .get() with no data or callback</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/echo-header/content-type&#x60;);\nnext();</code></pre></dd>\n        <dt>request .send() with no data only</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/5/pet&#x60;).type(&#x27;urlencoded&#x27;).send(&#x27;pet=tobi&#x27;);\nnext();</code></pre></dd>\n        <dt>request .send() with callback only</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .set(&#x27;Accept&#x27;, &#x27;foo/bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;foo/bar&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with json</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/json&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with application/json</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;application/json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/json&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with xml</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      // We can&#x27;t depend on mime module to be consistent with this\n      assert(res.text == &#x27;application/xml&#x27; || res.text == &#x27;text/xml&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with application/xml</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;application/xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/xml&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .end()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .send()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .set()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .set(object)</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set({ &#x27;Content-Type&#x27;: &#x27;text/plain&#x27; })\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST urlencoded</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .type(&#x27;urlencoded&#x27;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .type(&#x27;json&#x27;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json array</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send([1, 2, 3])\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(\n        &#x27;application/json&#x27;,\n        res.header[&#x27;content-type&#x27;].split(&#x27;;&#x27;)[0]\n      );\n      assert.equal(&#x27;[1,2,3]&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json default</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json contentType charset</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json; charset=UTF-8&#x27;)\n  .send({ data: [&#x27;data1&#x27;, &#x27;data2&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;{&#x22;data&#x22;:[&#x22;data1&#x22;,&#x22;data2&#x22;]}&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json contentType vendor</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/vnd.example+json&#x27;)\n  .send({ data: [&#x27;data1&#x27;, &#x27;data2&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;{&#x22;data&#x22;:[&#x22;data1&#x22;,&#x22;data2&#x22;]}&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST multiple .send() calls</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .send({ name: &#x27;Manny&#x27; })\n  .send({ species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST multiple .send() strings</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send(&#x27;user[name]=tj&#x27;)\n  .send(&#x27;user[email]=tj@vision-media.ca&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(\n        &#x27;application/x-www-form-urlencoded&#x27;,\n        res.header[&#x27;content-type&#x27;].split(&#x27;;&#x27;)[0]\n      );\n      assert.equal(\n        res.text,\n        &#x27;user[name]=tj&#x26;user[email]=tj@vision-media.ca&#x27;\n      );\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST with no data</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/empty-body&#x60;)\n  .send()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.noContent, &#x27;response should be .noContent&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET .type</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/pets&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;application/json&#x27;, res.type);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET Content-Type params</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/text&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;utf-8&#x27;, res.charset);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET json</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/pets&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.deepEqual(res.body, [&#x27;tobi&#x27;, &#x27;loki&#x27;, &#x27;jane&#x27;]);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET json-seq</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/json-seq&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.deepEqual(res.text, &#x27;\\u001E{&#x22;id&#x22;:1}\\n\\u001E{&#x22;id&#x22;:2}\\n&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET binary data</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/binary-data&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.deepEqual(res.body, binData);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET x-www-form-urlencoded</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.deepEqual(res.body, { foo: &#x27;bar&#x27; });\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET shorthand</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/foo&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;foo=bar&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>POST shorthand</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/0/pet&#x60;, { pet: &#x27;tobi&#x27; }, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>POST shorthand without callback</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/0/pet&#x60;, { pet: &#x27;tobi&#x27; }).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET querystring object with array</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ val: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { val: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object with array and primitives</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ array: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;], string: &#x27;foo&#x27;, number: 10 })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        array: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;],\n        string: &#x27;foo&#x27;,\n        number: 10\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object with two arrays</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ array1: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;], array2: [1, 2, 3] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        array1: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;],\n        array2: [1, 2, 3]\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ search: &#x27;Manny&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { search: &#x27;Manny&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring append original</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring?search=Manny&#x60;)\n  .query({ range: &#x27;1..5&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { search: &#x27;Manny&#x27;, range: &#x27;1..5&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring multiple objects</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ search: &#x27;Manny&#x27; })\n  .query({ range: &#x27;1..5&#x27; })\n  .query({ order: &#x27;desc&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring with strings</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;range=1..5&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring with strings and objects</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query({ order: &#x27;desc&#x27;, range: &#x27;1..5&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET shorthand payload goes to querystring</dt>\n        <dd><pre><code>request.get(\n  &#x60;${uri}/querystring&#x60;,\n  { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; },\n  (error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  }\n);</code></pre></dd>\n        <dt>HEAD shorthand payload goes to querystring</dt>\n        <dd><pre><code>request.head(\n  &#x60;${uri}/querystring-in-header&#x60;,\n  { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; },\n  (error, res) =&#x3E; {\n    try {\n      assert.deepEqual(JSON.parse(res.headers.query), {\n        foo: &#x27;FOO&#x27;,\n        bar: &#x27;BAR&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  }\n);</code></pre></dd>\n        <dt>request(method, url)</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request(url)</dt>\n        <dd><pre><code>request(&#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request(url, fn)</dt>\n        <dd><pre><code>request(&#x60;${uri}/foo&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.timeout(ms)</dt>\n        <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;).timeout(1000);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(error, &#x27;error missing&#x27;);\n    assert.equal(1000, error.timeout, &#x27;err.timeout missing&#x27;);\n    assert.equal(\n      &#x27;Timeout of 1000ms exceeded&#x27;,\n      error.message,\n      &#x27;err.message incorrect&#x27;\n    );\n    assert.equal(null, res);\n    assert(request_.timedout, true);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.timeout(ms) with redirect</dt>\n        <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/const&#x60;).timeout(1000);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(error, &#x27;error missing&#x27;);\n    assert.equal(1000, error.timeout, &#x27;err.timeout missing&#x27;);\n    assert.equal(\n      &#x27;Timeout of 1000ms exceeded&#x27;,\n      error.message,\n      &#x27;err.message incorrect&#x27;\n    );\n    assert.equal(null, res);\n    assert(request_.timedout, true);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request event</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/foo&#x60;)\n  .on(&#x27;request&#x27;, (request_) =&#x3E; {\n    try {\n      assert.equal(&#x60;${uri}/foo&#x60;, request_.url);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  })\n  .end();</code></pre></dd>\n        <dt>response event</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/foo&#x60;)\n  .on(&#x27;response&#x27;, (res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.body.foo);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  })\n  .end();</code></pre></dd>\n        <dt>response should set statusCode</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/ok&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.strictEqual(res.statusCode, 200);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.toJSON()</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    const index = (res.request || res.req).toJSON();\n    for (const property of [&#x27;url&#x27;, &#x27;method&#x27;, &#x27;data&#x27;, &#x27;headers&#x27;]) {\n      assert(index.hasOwnProperty(property));\n    }\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>.retry(count)</h1>\n      <dl>\n        <dt>should not retry if passed &#x22;0&#x22;</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(0)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry if passed an invalid number</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(-2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry if passed undefined</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(undefined)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle server error after repeat attempt</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should retry if passed nothing</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry()\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(1, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should retry if passed &#x22;true&#x22;</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(true)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(1, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server error</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error/ok/${uniqid()}&#x60;)\n  .query({ qs: &#x27;present&#x27; })\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert(res.text, &#x27;res.text&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle server timeout error after repeat attempt</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/delay/400&#x60;)\n  .timeout(200)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(\n        &#x27;number&#x27;,\n        typeof error.timeout,\n        &#x27;expected an error with .timeout&#x27;\n      );\n      assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server timeout</dt>\n        <dd><pre><code>const url = &#x60;/delay/1200/ok/${uniqid()}?built=in&#x60;;\nrequest\n  .get(base + url)\n  .query(&#x27;string=ified&#x27;)\n  .query({ json: &#x27;ed&#x27; })\n  .timeout(600)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert.equal(res.text, &#x60;ok = ${url}&#x26;string=ified&#x26;json=ed&#x60;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server timeout when using .then(fulfill, reject)</dt>\n        <dd><pre><code>const url = &#x60;/delay/1200/ok/${uniqid()}?built=in&#x60;;\nrequest\n  .get(base + url)\n  .query(&#x27;string=ified&#x27;)\n  .query({ json: &#x27;ed&#x27; })\n  .timeout(600)\n  .retry(1)\n  .then((res, error) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert.equal(res.text, &#x60;ok = ${url}&#x26;string=ified&#x26;json=ed&#x60;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should correctly abort a retry attempt</dt>\n        <dd><pre><code>let aborted = false;\nconst request_ = request.get(&#x60;${base}/delay/400&#x60;).timeout(200).retry(2);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\nrequest_.on(&#x27;abort&#x27;, () =&#x3E; {\n  aborted = true;\n});\nsetTimeout(() =&#x3E; {\n  request_.abort();\n  setTimeout(() =&#x3E; {\n    try {\n      assert(aborted, &#x27;should be aborted&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  }, 150);\n}, 150);</code></pre></dd>\n        <dt>should correctly retain header fields</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error/ok/${uniqid()}&#x60;)\n  .query({ qs: &#x27;present&#x27; })\n  .retry(2)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry on 4xx responses</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/bad-request&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(0, error.retries, &#x27;expected an error with 0 .retries&#x27;);\n      assert.equal(400, error.status, &#x27;expected an error status of 400&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should execute callback on retry if passed</dt>\n        <dd><pre><code>let callbackCallCount = 0;\nfunction retryCallback(request) {\n  callbackCallCount++;\n}\nrequest\n  .get(&#x60;${base}/error&#x60;)\n  .retry(2, retryCallback)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      assert.equal(\n        2,\n        callbackCallCount,\n        &#x27;expected the callback to be called on each retry&#x27;\n      );\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>.timeout(ms)</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>when timeout is exceeded</h1>\n          <dl>\n            <dt>should error</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should error in promise interface </dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout(150)\n  .catch((err) =&#x3E; {\n    assert(err, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof err.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, err.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should handle gzip timeout</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/zip&#x60;)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should handle buffer timeout</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/json&#x60;)\n  .buffer(true)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should error on deadline</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ deadline: 150 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should support setting individual options</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ deadline: 10 })\n  .timeout({ response: 99_999 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    assert.equal(&#x27;ETIME&#x27;, error.errno);\n    done();\n  });</code></pre></dd>\n            <dt>should error on response</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ response: 150 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    assert.equal(&#x27;ETIMEDOUT&#x27;, error.errno);\n    done();\n  });</code></pre></dd>\n            <dt>should accept slow body with fast response</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/slowbody&#x60;)\n  .timeout({ response: 1000 })\n  .on(&#x27;progress&#x27;, () =&#x3E; {\n    // This only makes the test faster without relying on arbitrary timeouts\n    request.get(&#x60;${base}/delay/slowbody/finish&#x60;).end();\n  })\n  .end(done);</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>use</h1>\n          <dl>\n            <dt>should use plugin success</dt>\n            <dd><pre><code>const now = &#x60;${Date.now()}&#x60;;\nfunction uuid(request_) {\n  request_.set(&#x27;X-UUID&#x27;, now);\n  return request_;\n}\nfunction prefix(request_) {\n  request_.url = uri + request_.url;\n  return request_;\n}\nrequest\n  .get(&#x27;/echo&#x27;)\n  .use(uuid)\n  .use(prefix)\n  .end((error, res) =&#x3E; {\n    assert.strictEqual(res.statusCode, 200);\n    assert.equal(res.get(&#x27;X-UUID&#x27;), now);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>subclass</h1>\n      <dl>\n        <dt>should be an instance of Request</dt>\n        <dd><pre><code>const request_ = request.get(&#x27;/&#x27;);\nassert(request_ instanceof request.Request);</code></pre></dd>\n        <dt>should use patched subclass</dt>\n        <dd><pre><code>assert(OriginalRequest);\nlet constructorCalled;\nlet sendCalled;\nfunction NewRequest(...args) {\n  constructorCalled = true;\n  OriginalRequest.apply(this, args);\n}\nNewRequest.prototype = Object.create(OriginalRequest.prototype);\nNewRequest.prototype.send = function () {\n  sendCalled = true;\n  return this;\n};\nrequest.Request = NewRequest;\nconst request_ = request.get(&#x27;/&#x27;).send();\nassert(constructorCalled);\nassert(sendCalled);\nassert(request_ instanceof NewRequest);\nassert(request_ instanceof OriginalRequest);</code></pre></dd>\n        <dt>should use patched subclass in agent too</dt>\n        <dd><pre><code>if (!request.agent) return; // Node-only\nfunction NewRequest(...args) {\n  OriginalRequest.apply(this, args);\n}\nNewRequest.prototype = Object.create(OriginalRequest.prototype);\nrequest.Request = NewRequest;\nconst request_ = request.agent().del(&#x27;/&#x27;);\nassert(request_ instanceof NewRequest);\nassert(request_ instanceof OriginalRequest);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>persistent agent</h1>\n          <dl>\n            <dt>should gain a session on POST</dt>\n            <dd><pre><code>agent3.post(&#x60;${base}/signin&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should start with empty session (set cookies)</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  should.exist(res.headers[&#x27;set-cookie&#x27;]);\n  done();\n});</code></pre></dd>\n            <dt>should gain a session (cookies already set)</dt>\n            <dd><pre><code>agent1.post(&#x60;${base}/signin&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should persist cookies across requests</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n      })</code></pre></dd>\n            <dt>should have the cookie set in the end callback</dt>\n            <dd><pre><code>agent4\n        .post(&#x60;${base}/setcookie&#x60;)\n        .then(() =&#x3E; agent4.get(&#x60;${base}/getcookie&#x60;))\n        .then((res) =&#x3E; {\n          res.should.have.status(200);\n          assert.strictEqual(res.text, &#x27;jar&#x27;);\n        })</code></pre></dd>\n            <dt>should not share cookies</dt>\n            <dd><pre><code>agent2.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  done();\n});</code></pre></dd>\n            <dt>should not lose cookies between agents</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n      })</code></pre></dd>\n            <dt>should be able to follow redirects</dt>\n            <dd><pre><code>agent1.get(base).then((res) =&#x3E; {\n        res.should.have.status(200);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should be able to post redirects</dt>\n            <dd><pre><code>agent1\n        .post(&#x60;${base}/redirect&#x60;)\n        .send({ foo: &#x27;bar&#x27;, baz: &#x27;blaaah&#x27; })\n        .then((res) =&#x3E; {\n          res.should.have.status(200);\n          res.text.should.containEql(&#x27;simple&#x27;);\n          res.redirects.should.eql([&#x60;${base}/simple&#x60;]);\n        })</code></pre></dd>\n            <dt>should be able to limit redirects</dt>\n            <dd><pre><code>agent1\n  .get(base)\n  .redirects(0)\n  .end((error, res) =&#x3E; {\n    should.exist(error);\n    res.should.have.status(302);\n    res.redirects.should.eql([]);\n    res.header.location.should.equal(&#x27;/dashboard&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should be able to create a new session (clear cookie)</dt>\n            <dd><pre><code>agent1.post(&#x60;${base}/signout&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.exist(res.headers[&#x27;set-cookie&#x27;]);\n      })</code></pre></dd>\n            <dt>should regenerate with an empty session</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Basic auth</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>when credentials are present in url</h1>\n          <dl>\n            <dt>should set Authorization</dt>\n            <dd><pre><code>const new_url = URL.parse(base);\nnew_url.auth = &#x27;tobi:learnboost&#x27;;\nnew_url.pathname = &#x27;/basic-auth&#x27;;\nrequest.get(URL.format(new_url)).end((error, res) =&#x3E; {\n  res.status.should.equal(200);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.auth(user, pass)</h1>\n          <dl>\n            <dt>should set Authorization</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/basic-auth&#x60;)\n  .auth(&#x27;tobi&#x27;, &#x27;learnboost&#x27;)\n  .end((error, res) =&#x3E; {\n    res.status.should.equal(200);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.auth(user + &#x22;:&#x22; + pass)</h1>\n          <dl>\n            <dt>should set authorization</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/basic-auth/again&#x60;)\n  .auth(&#x27;tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    res.status.should.eql(200);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[node] request</h1>\n      <dl>\n        <dt>should send body with .get().send()</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;wahoo&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <section class=\"suite\">\n          <h1>with an url</h1>\n          <dl>\n            <dt>should preserve the encoding of the url</dt>\n            <dd><pre><code>request.get(&#x60;${base}/url?a=(b%29&#x60;).end((error, res) =&#x3E; {\n  assert.equal(&#x27;/url?a=(b%29&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with an object</h1>\n          <dl>\n            <dt>should format the url</dt>\n            <dd><pre><code>request.get(url.parse(&#x60;${base}/login&#x60;)).then((res) =&#x3E; {\n        assert(res.ok);\n      })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>without a schema</h1>\n          <dl>\n            <dt>should default to http</dt>\n            <dd><pre><code>request.get(&#x60;${base}/login&#x60;).then((res) =&#x3E; {\n        assert.equal(res.status, 200);\n      })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.toJSON()</h1>\n          <dl>\n            <dt>should describe the response</dt>\n            <dd><pre><code>request\n        .post(&#x60;${base}/echo&#x60;)\n        .send({ foo: &#x27;baz&#x27; })\n        .then((res) =&#x3E; {\n          const object = res.toJSON();\n          assert.equal(&#x27;object&#x27;, typeof object.header);\n          assert.equal(&#x27;object&#x27;, typeof object.req);\n          assert.equal(200, object.status);\n          assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;baz&#x22;}&#x27;, object.text);\n        })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.links</h1>\n          <dl>\n            <dt>should default to an empty object</dt>\n            <dd><pre><code>request.get(&#x60;${base}/login&#x60;).then((res) =&#x3E; {\n        res.links.should.eql({});\n      })</code></pre></dd>\n            <dt>should parse the Link header field</dt>\n            <dd><pre><code>request.get(&#x60;${base}/links&#x60;).end((error, res) =&#x3E; {\n  res.links.next.should.equal(\n    &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x27;\n  );\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.unset(field)</h1>\n          <dl>\n            <dt>should remove the header field</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .unset(&#x27;User-Agent&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.equal(void 0, res.header[&#x27;user-agent&#x27;]);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>case-insensitive</h1>\n          <dl>\n            <dt>should set/get header fields case-insensitively</dt>\n            <dd><pre><code>const r = request.post(&#x60;${base}/echo&#x60;);\nr.set(&#x27;MiXeD&#x27;, &#x27;helloes&#x27;);\nassert.strictEqual(r.get(&#x27;mixed&#x27;), &#x27;helloes&#x27;);</code></pre></dd>\n            <dt>should unset header fields case-insensitively</dt>\n            <dd><pre><code>const r = request.post(&#x60;${base}/echo&#x60;);\nr.set(&#x27;MiXeD&#x27;, &#x27;helloes&#x27;);\nr.unset(&#x27;MIXED&#x27;);\nassert.strictEqual(r.get(&#x27;mixed&#x27;), undefined);</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.write(str)</h1>\n          <dl>\n            <dt>should write the given data</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.set(&#x27;Content-Type&#x27;, &#x27;application/json&#x27;);\nassert.equal(&#x27;boolean&#x27;, typeof request_.write(&#x27;{&#x22;name&#x22;&#x27;));\nassert.equal(&#x27;boolean&#x27;, typeof request_.write(&#x27;:&#x22;tobi&#x22;}&#x27;));\nrequest_.end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.pipe(stream)</h1>\n          <dl>\n            <dt>should pipe the response to the given stream</dt>\n            <dd><pre><code>const stream = new EventEmitter();\nstream.buf = &#x27;&#x27;;\nstream.writable = true;\nstream.write = function (chunk) {\n  this.buf += chunk;\n};\nstream.end = function () {\n  this.buf.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  done();\n};\nrequest.post(&#x60;${base}/echo&#x60;).send(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;).pipe(stream);</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.buffer()</h1>\n          <dl>\n            <dt>should enable buffering</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/custom&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(&#x27;custom stuff&#x27;, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n            <dt>should take precedence over request.buffer[&#x27;someMimeType&#x27;] = false</dt>\n            <dd><pre><code>const type = &#x27;application/barbaz&#x27;;\nconst send = &#x27;some text&#x27;;\nrequest.buffer[type] = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.buffer(false)</h1>\n          <dl>\n            <dt>should disable buffering</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-dog&#x27;)\n  .send(&#x27;hello this is dog&#x27;)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(&#x27;hello this is dog&#x27;);\n      done();\n    });\n  });</code></pre></dd>\n            <dt>should take precedence over request.buffer[&#x27;someMimeType&#x27;] = true</dt>\n            <dd><pre><code>const type = &#x27;application/foobar&#x27;;\nconst send = &#x27;hello this is a dog&#x27;;\nrequest.buffer[type] = true;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.withCredentials()</h1>\n          <dl>\n            <dt>should not throw an error when using the client-side &#x22;withCredentials&#x22; method</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/custom&#x60;)\n  .withCredentials()\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent()</h1>\n          <dl>\n            <dt>should return the defaut agent</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.agent().should.equal(false);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent(undefined)</h1>\n          <dl>\n            <dt>should set an agent to undefined and ensure it is chainable</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/echo&#x60;);\nconst returnValue = request_.agent(undefined);\nreturnValue.should.equal(request_);\nassert.strictEqual(request_.agent(), undefined);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent(new http.Agent())</h1>\n          <dl>\n            <dt>should set passed agent</dt>\n            <dd><pre><code>const http = require(&#x27;http&#x27;);\nconst request_ = request.get(&#x60;${base}/echo&#x60;);\nconst agent = new http.Agent();\nconst returnValue = request_.agent(agent);\nreturnValue.should.equal(request_);\nrequest_.agent().should.equal(agent);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with a content type other than application/json or text/*</h1>\n          <dl>\n            <dt>should still use buffering</dt>\n            <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-dog&#x27;)\n  .send(&#x27;hello this is dog&#x27;)\n  .then((res) =&#x3E; {\n    assert.equal(null, res.text);\n    assert.equal(res.body.toString(), &#x27;hello this is dog&#x27;);\n    res.buffered.should.be.true;\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>content-length</h1>\n          <dl>\n            <dt>should be set to the byte length of a non-buffer object</dt>\n            <dd><pre><code>const decoder = new StringDecoder(&#x27;utf8&#x27;);\nlet img = fs.readFileSync(&#x60;${__dirname}/fixtures/test.png&#x60;);\nimg = decoder.write(img);\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-image&#x27;)\n  .send(img)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(!res.buffered);\n    assert.equal(res.header[&#x27;content-length&#x27;], Buffer.byteLength(img));\n    done();\n  });</code></pre></dd>\n            <dt>should be set to the length of a buffer object</dt>\n            <dd><pre><code>const img = fs.readFileSync(&#x60;${__dirname}/fixtures/test.png&#x60;);\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-image&#x27;)\n  .send(img)\n  .buffer(true)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.buffered);\n    assert.equal(res.header[&#x27;content-length&#x27;], img.length);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.buffer[&#x27;someMimeType&#x27;]</h1>\n      <dl>\n        <dt>should respect that agent.buffer(true) takes precedent</dt>\n        <dd><pre><code>const agent = request.agent();\nagent.buffer(true);\nconst type = &#x27;application/somerandomtype&#x27;;\nconst send = &#x27;somerandomtext&#x27;;\nrequest.buffer[type] = false;\nagent\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n        <dt>should respect that agent.buffer(false) takes precedent</dt>\n        <dd><pre><code>const agent = request.agent();\nagent.buffer(false);\nconst type = &#x27;application/barrr&#x27;;\nconst send = &#x27;some random text2&#x27;;\nrequest.buffer[type] = true;\nagent\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n        <dt>should disable buffering for that mimetype when false</dt>\n        <dd><pre><code>const type = &#x27;application/bar&#x27;;\nconst send = &#x27;some random text&#x27;;\nrequest.buffer[type] = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n        <dt>should enable buffering for that mimetype when true</dt>\n        <dd><pre><code>const type = &#x27;application/baz&#x27;;\nconst send = &#x27;woooo&#x27;;\nrequest.buffer[type] = true;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n        <dt>should fallback to default handling for that mimetype when undefined</dt>\n        <dd><pre><code>const type = &#x27;application/bazzz&#x27;;\nconst send = &#x27;woooooo&#x27;;\nreturn request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .then((res) =&#x3E; {\n    assert.equal(res.type, type);\n    assert.equal(send, res.body.toString());\n    assert(res.buffered);\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>exports</h1>\n      <dl>\n        <dt>should expose .protocols</dt>\n        <dd><pre><code>Object.keys(request.protocols).should.eql([&#x27;http:&#x27;, &#x27;https:&#x27;, &#x27;http2:&#x27;]);</code></pre></dd>\n        <dt>should expose .serialize</dt>\n        <dd><pre><code>Object.keys(request.serialize).should.eql([\n  &#x27;application/x-www-form-urlencoded&#x27;,\n  &#x27;application/json&#x27;\n]);</code></pre></dd>\n        <dt>should expose .parse</dt>\n        <dd><pre><code>Object.keys(request.parse).should.eql([\n  &#x27;application/x-www-form-urlencoded&#x27;,\n  &#x27;application/json&#x27;,\n  &#x27;text&#x27;,\n  &#x27;application/json-seq&#x27;,\n  &#x27;application/octet-stream&#x27;,\n  &#x27;application/pdf&#x27;,\n  &#x27;image&#x27;\n]);</code></pre></dd>\n        <dt>should export .buffer</dt>\n        <dd><pre><code>Object.keys(request.buffer).should.eql([]);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>flags</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>with 4xx response</h1>\n          <dl>\n            <dt>should set res.error and res.clientError</dt>\n            <dd><pre><code>request.get(&#x60;${base}/notfound&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(!res.ok, &#x27;response should not be ok&#x27;);\n  assert(res.error, &#x27;response should be an error&#x27;);\n  assert(res.clientError, &#x27;response should be a client error&#x27;);\n  assert(!res.serverError, &#x27;response should not be a server error&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 5xx response</h1>\n          <dl>\n            <dt>should set res.error and res.serverError</dt>\n            <dd><pre><code>request.get(&#x60;${base}/error&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(!res.ok, &#x27;response should not be ok&#x27;);\n  assert(!res.notFound, &#x27;response should not be notFound&#x27;);\n  assert(res.error, &#x27;response should be an error&#x27;);\n  assert(!res.clientError, &#x27;response should not be a client error&#x27;);\n  assert(res.serverError, &#x27;response should be a server error&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 404 Not Found</h1>\n          <dl>\n            <dt>should res.notFound</dt>\n            <dd><pre><code>request.get(&#x60;${base}/notfound&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.notFound, &#x27;response should be .notFound&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 400 Bad Request</h1>\n          <dl>\n            <dt>should set req.badRequest</dt>\n            <dd><pre><code>request.get(&#x60;${base}/bad-request&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.badRequest, &#x27;response should be .badRequest&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 401 Bad Request</h1>\n          <dl>\n            <dt>should set res.unauthorized</dt>\n            <dd><pre><code>request.get(&#x60;${base}/unauthorized&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.unauthorized, &#x27;response should be .unauthorized&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 406 Not Acceptable</h1>\n          <dl>\n            <dt>should set res.notAcceptable</dt>\n            <dd><pre><code>request.get(&#x60;${base}/not-acceptable&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.notAcceptable, &#x27;response should be .notAcceptable&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 204 No Content</h1>\n          <dl>\n            <dt>should set res.noContent</dt>\n            <dd><pre><code>request.get(&#x60;${base}/no-content&#x60;).end((error, res) =&#x3E; {\n  assert(!error);\n  assert(res.noContent, &#x27;response should be .noContent&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 201 Created</h1>\n          <dl>\n            <dt>should set res.created</dt>\n            <dd><pre><code>request.post(&#x60;${base}/created&#x60;).end((error, res) =&#x3E; {\n  assert(!error);\n  assert(res.created, &#x27;response should be .created&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 422 Unprocessable Entity</h1>\n          <dl>\n            <dt>should set res.unprocessableEntity</dt>\n            <dd><pre><code>request.post(&#x60;${base}/unprocessable-entity&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(\n    res.unprocessableEntity,\n    &#x27;response should be .unprocessableEntity&#x27;\n  );\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Merging objects</h1>\n      <dl>\n        <dt>Don&#x27;t mix Buffer and JSON</dt>\n        <dd><pre><code>assert.throws(() =&#x3E; {\n  request\n    .post(&#x27;/echo&#x27;)\n    .send(Buffer.from(&#x27;some buffer&#x27;))\n    .send({ allowed: false });\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(String)</h1>\n      <dl>\n        <dt>should default to &#x22;form&#x22;</dt>\n        <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .send(&#x27;user[name]=tj&#x27;)\n  .send(&#x27;user[email]=tj@vision-media.ca&#x27;)\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.body.should.eql({\n      user: { name: &#x27;tj&#x27;, email: &#x27;tj@vision-media.ca&#x27; }\n    });\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>application/x-www-form-urlencoded</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${base}/form-data&#x60;).end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;pet[name]=manny&#x27;);\n  res.body.should.eql({ pet: { name: &#x27;manny&#x27; } });\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>https</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>certificate authority</h1>\n          <dl>\n            <section class=\"suite\">\n              <h1>request</h1>\n              <dl>\n                <dt>should give a good response</dt>\n                <dd><pre><code>request\n  .get(testEndpoint)\n  .ca(ca)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n                <dt>should reject unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(testEndpoint)\n  .trustLocalhost(false)\n  .then(\n    () =&#x3E; {\n      throw new Error(&#x27;Allows MITM&#x27;);\n    },\n    () =&#x3E; {}\n  );</code></pre></dd>\n                <dt>should not reject unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(testEndpoint)\n  .disableTLSCerts()\n  .then(({ status }) =&#x3E; {\n    assert.strictEqual(status, 200);\n  });</code></pre></dd>\n                <dt>should trust localhost unauthorized response</dt>\n                <dd><pre><code>return request.get(testEndpoint).trustLocalhost(true);</code></pre></dd>\n                <dt>should trust overriden localhost unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(&#x60;https://example.com:${server.address().port}&#x60;)\n  .connect(&#x27;127.0.0.1&#x27;)\n  .trustLocalhost();</code></pre></dd>\n              </dl>\n            </section>\n            <section class=\"suite\">\n              <h1>.agent</h1>\n              <dl>\n                <dt>should be able to make multiple requests without redefining the certificate</dt>\n                <dd><pre><code>const agent = request.agent({ ca });\nagent.get(testEndpoint).end((error, res) =&#x3E; {\n  assert.ifError(error);\n  assert(res.ok);\n  assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n  agent.get(url.parse(testEndpoint)).end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n    done();\n  });\n});</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>client certificates</h1>\n          <dl>\n            <section class=\"suite\">\n              <h1>request</h1>\n              <dl>\n              </dl>\n            </section>\n            <section class=\"suite\">\n              <h1>.agent</h1>\n              <dl>\n              </dl>\n            </section>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>image/png</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${base}/image&#x60;).end((error, res) =&#x3E; {\n  res.type.should.equal(&#x27;image/png&#x27;);\n  Buffer.isBuffer(res.body).should.be.true();\n  (res.body.length - img.length).should.equal(0);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>application/octet-stream</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/image-as-octets&#x60;)\n  .buffer(true) // that&#x27;s tech debt :(\n  .end((error, res) =&#x3E; {\n    res.type.should.equal(&#x27;application/octet-stream&#x27;);\n    Buffer.isBuffer(res.body).should.be.true();\n    (res.body.length - img.length).should.equal(0);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>application/octet-stream</h1>\n          <dl>\n            <dt>should parse the body (using responseType)</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/image-as-octets&#x60;)\n  .responseType(&#x27;blob&#x27;)\n  .end((error, res) =&#x3E; {\n    res.type.should.equal(&#x27;application/octet-stream&#x27;);\n    Buffer.isBuffer(res.body).should.be.true();\n    (res.body.length - img.length).should.equal(0);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>zlib</h1>\n      <dl>\n        <dt>should deflate the content</dt>\n        <dd><pre><code>request.get(base).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.equal(subject);\n  res.headers[&#x27;content-length&#x27;].should.be.below(subject.length);\n  done();\n});</code></pre></dd>\n        <dt>should protect from zip bombs</dt>\n        <dd><pre><code>request\n  .get(base)\n  .buffer(true)\n  .maxResponseSize(1)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;Maximum response size reached&#x27;, error &#x26;&#x26; error.message);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should ignore trailing junk</dt>\n        <dd><pre><code>request.get(&#x60;${base}/junk&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.equal(subject);\n  done();\n});</code></pre></dd>\n        <dt>should ignore missing data</dt>\n        <dd><pre><code>request.get(&#x60;${base}/chopped&#x60;).end((error, res) =&#x3E; {\n  assert.equal(undefined, error);\n  res.should.have.status(200);\n  res.text.should.startWith(subject);\n  done();\n});</code></pre></dd>\n        <dt>should handle corrupted responses</dt>\n        <dd><pre><code>request.get(&#x60;${base}/corrupt&#x60;).end((error, res) =&#x3E; {\n  assert(error, &#x27;missing error&#x27;);\n  assert(!res, &#x27;response should not be defined&#x27;);\n  done();\n});</code></pre></dd>\n        <dt>should handle no content with gzip header</dt>\n        <dd><pre><code>request.get(&#x60;${base}/nocontent&#x60;).end((error, res) =&#x3E; {\n  assert.ifError(error);\n  assert(res);\n  res.should.have.status(204);\n  res.text.should.equal(&#x27;&#x27;);\n  res.headers.should.not.have.property(&#x27;content-length&#x27;);\n  done();\n});</code></pre></dd>\n        <section class=\"suite\">\n          <h1>without encoding set</h1>\n          <dl>\n            <dt>should buffer if asked</dt>\n            <dd><pre><code>return request\n  .get(&#x60;${base}/binary&#x60;)\n  .buffer(true)\n  .then((res) =&#x3E; {\n    res.should.have.status(200);\n    assert(res.headers[&#x27;content-length&#x27;]);\n    assert(res.body.byteLength);\n    assert.equal(subject, res.body.toString());\n  });</code></pre></dd>\n            <dt>should emit buffers</dt>\n            <dd><pre><code>request.get(&#x60;${base}/binary&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.headers[&#x27;content-length&#x27;].should.be.below(subject.length);\n  res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n    chunk.should.have.length(subject.length);\n  });\n  res.on(&#x27;end&#x27;, done);\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.lookup()</h1>\n      <dl>\n        <dt>should set a custom lookup</dt>\n        <dd><pre><code>const r = request.get(&#x60;${base}/ok&#x60;).lookup(myLookup);\nassert(r.lookup() === myLookup);\nr.then((res) =&#x3E; {\n  res.text.should.equal(&#x27;ok&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Multipart</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>#field(name, value)</h1>\n          <dl>\n            <dt>should set a multipart field value</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.field(&#x27;user[name]&#x27;, &#x27;tobi&#x27;);\nrequest_.field(&#x27;user[age]&#x27;, &#x27;2&#x27;);\nrequest_.field(&#x27;user[species]&#x27;, &#x27;ferret&#x27;);\nreturn request_.then((res) =&#x3E; {\n  res.body[&#x27;user[name]&#x27;].should.equal(&#x27;tobi&#x27;);\n  res.body[&#x27;user[age]&#x27;].should.equal(&#x27;2&#x27;);\n  res.body[&#x27;user[species]&#x27;].should.equal(&#x27;ferret&#x27;);\n});</code></pre></dd>\n            <dt>should work with file attachments</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.field(&#x27;name&#x27;, &#x27;Tobi&#x27;);\nrequest_.attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;);\nrequest_.field(&#x27;species&#x27;, &#x27;ferret&#x27;);\nreturn request_.then((res) =&#x3E; {\n  res.body.name.should.equal(&#x27;Tobi&#x27;);\n  res.body.species.should.equal(&#x27;ferret&#x27;);\n  const html = res.files.document;\n  html.originalFilename.should.equal(&#x27;user.html&#x27;);\n  html.mimetype.should.equal(&#x27;text/html&#x27;);\n  read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#attach(name, path)</h1>\n          <dl>\n            <dt>should attach a file</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.attach(&#x27;one&#x27;, &#x27;test/node/fixtures/user.html&#x27;);\nrequest_.attach(&#x27;two&#x27;, &#x27;test/node/fixtures/user.json&#x27;);\nrequest_.attach(&#x27;three&#x27;, &#x27;test/node/fixtures/user.txt&#x27;);\nreturn request_.then((res) =&#x3E; {\n  const html = res.files.one;\n  const json = res.files.two;\n  const text = res.files.three;\n  html.originalFilename.should.equal(&#x27;user.html&#x27;);\n  html.mimetype.should.equal(&#x27;text/html&#x27;);\n  read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n  json.originalFilename.should.equal(&#x27;user.json&#x27;);\n  json.mimetype.should.equal(&#x27;application/json&#x27;);\n  read(json.filepath).should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  text.originalFilename.should.equal(&#x27;user.txt&#x27;);\n  text.mimetype.should.equal(&#x27;text/plain&#x27;);\n  read(text.filepath).should.equal(&#x27;Tobi&#x27;);\n});</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when a file does not exist</h1>\n              <dl>\n                <dt>should fail the request with an error</dt>\n                <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.attach(&#x27;name&#x27;, &#x27;foo&#x27;);\n// request_.attach(&#x27;name2&#x27;, &#x27;bar&#x27;);\n// request_.attach(&#x27;name3&#x27;, &#x27;baz&#x27;);\nrequest_.end((error, res) =&#x3E; {\n  assert.ok(Boolean(error), &#x27;Request should have failed.&#x27;);\n  error.code.should.equal(&#x27;ENOENT&#x27;);\n  error.message.should.containEql(&#x27;ENOENT&#x27;);\n  if (IS_WINDOWS) {\n    error.path.toLowerCase().should.equal(\n      getFullPath(&#x27;foo&#x27;).toLowerCase()\n    );\n  } else {\n    error.path.should.equal(getFullPath(&#x27;foo&#x27;));\n  }\n  done();\n});</code></pre></dd>\n                <dt>promise should fail</dt>\n                <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .field({ a: 1, b: 2 })\n  .attach(&#x27;c&#x27;, &#x27;does-not-exist.txt&#x27;)\n  .then(\n    (res) =&#x3E; assert.fail(&#x27;It should not allow this&#x27;),\n    (err) =&#x3E; {\n      err.code.should.equal(&#x27;ENOENT&#x27;);\n      if (IS_WINDOWS) {\n        err.path.toLowerCase().should.equal(\n          getFullPath(&#x27;does-not-exist.txt&#x27;).toLowerCase()\n        );\n      } else {\n        err.path.should.equal(getFullPath(&#x27;does-not-exist.txt&#x27;));\n      }\n    }\n  );</code></pre></dd>\n                <dt>should report ENOENT via the callback</dt>\n                <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;name&#x27;, &#x27;file-does-not-exist&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ok(Boolean(error), &#x27;Request should have failed&#x27;);\n    error.code.should.equal(&#x27;ENOENT&#x27;);\n    done();\n  });</code></pre></dd>\n                <dt>should report ENOENT via Promise</dt>\n                <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;name&#x27;, &#x27;file-does-not-exist&#x27;)\n  .then(\n    (res) =&#x3E; assert.fail(&#x27;Request should have failed&#x27;),\n    (err) =&#x3E; err.code.should.equal(&#x27;ENOENT&#x27;)\n  );</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#attach(name, path, filename)</h1>\n          <dl>\n            <dt>should use the custom filename</dt>\n            <dd><pre><code>request\n        .post(&#x60;${base}/echo&#x60;)\n        .attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;, &#x27;doc.html&#x27;)\n        .then((res) =&#x3E; {\n          const html = res.files.document;\n          html.originalFilename.should.equal(&#x27;doc.html&#x27;);\n          html.mimetype.should.equal(&#x27;text/html&#x27;);\n          read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n        })</code></pre></dd>\n            <dt>should fire progress event</dt>\n            <dd><pre><code>let loaded = 0;\nlet total = 0;\nlet uploadEventWasFired = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;)\n  .on(&#x27;progress&#x27;, (event) =&#x3E; {\n    total = event.total;\n    loaded = event.loaded;\n    if (event.direction === &#x27;upload&#x27;) {\n      uploadEventWasFired = true;\n    }\n  })\n  .end((error, res) =&#x3E; {\n    if (error) return done(error);\n    const html = res.files.document;\n    html.originalFilename.should.equal(&#x27;user.html&#x27;);\n    html.mimetype.should.equal(&#x27;text/html&#x27;);\n    read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n    total.should.equal(223);\n    loaded.should.equal(223);\n    uploadEventWasFired.should.equal(true);\n    done();\n  });</code></pre></dd>\n            <dt>filesystem errors should be caught</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;filedata&#x27;, &#x27;test/node/fixtures/non-existent-file.ext&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ok(Boolean(error), &#x27;Request should have failed.&#x27;);\n    error.code.should.equal(&#x27;ENOENT&#x27;);\n    if (IS_WINDOWS) {\n      error.path.toLowerCase().should.equal(\n        getFullPath(&#x27;test/node/fixtures/non-existent-file.ext&#x27;).toLowerCase()\n      );\n    } else {\n      error.path.should.equal(\n        getFullPath(&#x27;test/node/fixtures/non-existent-file.ext&#x27;)\n      );\n    }\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#field(name, val)</h1>\n          <dl>\n            <dt>should set a multipart field value</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .field(&#x27;first-name&#x27;, &#x27;foo&#x27;)\n  .field(&#x27;last-name&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    if (error) done(error);\n    res.should.be.ok();\n    res.body[&#x27;first-name&#x27;].should.equal(&#x27;foo&#x27;);\n    res.body[&#x27;last-name&#x27;].should.equal(&#x27;bar&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#field(object)</h1>\n          <dl>\n            <dt>should set multiple multipart fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .field({ &#x27;first-name&#x27;: &#x27;foo&#x27;, &#x27;last-name&#x27;: &#x27;bar&#x27; })\n  .end((error, res) =&#x3E; {\n    if (error) done(error);\n    res.should.be.ok();\n    res.body[&#x27;first-name&#x27;].should.equal(&#x27;foo&#x27;);\n    res.body[&#x27;last-name&#x27;].should.equal(&#x27;bar&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>with network error</h1>\n      <dl>\n        <dt>should error</dt>\n        <dd><pre><code>request.get(&#x60;http://localhost:${this.port}/&#x60;).end((error, res) =&#x3E; {\n  assert(error, &#x27;expected an error&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>not modified</h1>\n          <dl>\n            <dt>should start with 200</dt>\n            <dd><pre><code>request.get(&#x60;${base}/if-mod&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.match(/^\\d+$/);\n  ts = Number(res.text);\n  done();\n});</code></pre></dd>\n            <dt>should then be 304</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/if-mod&#x60;)\n  .set(&#x27;If-Modified-Since&#x27;, new Date(ts).toUTCString())\n  .end((error, res) =&#x3E; {\n    res.should.have.status(304);\n    // res.text.should.be.empty\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.parse(fn)</h1>\n      <dl>\n        <dt>should take precedence over default parsers</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse(request.parse[&#x27;application/json&#x27;])\n  .end((error, res) =&#x3E; {\n    assert(res.ok);\n    assert.equal(&#x27;{&#x22;name&#x22;:&#x22;manny&#x22;}&#x27;, res.text);\n    assert.equal(&#x27;manny&#x27;, res.body.name);\n    done();\n  });</code></pre></dd>\n        <dt>should be the only parser</dt>\n        <dd><pre><code>request\n      .get(&#x60;${base}/image&#x60;)\n      .buffer(false)\n      .parse((res, fn) =&#x3E; {\n        res.on(&#x27;data&#x27;, () =&#x3E; {});\n      })\n      .then((res) =&#x3E; {\n        assert(res.ok);\n        assert.strictEqual(res.text, undefined);\n        res.body.should.eql({});\n      })</code></pre></dd>\n        <dt>should emit error if parser throws</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse(() =&#x3E; {\n    throw new Error(&#x27;I am broken&#x27;);\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    error.message.should.equal(&#x27;I am broken&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n        <dt>should emit error if parser returns an error</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse((res, fn) =&#x3E; {\n    fn(new Error(&#x27;I am broken&#x27;));\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    error.message.should.equal(&#x27;I am broken&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n        <dt>should not emit error on chunked json</dt>\n        <dd><pre><code>request.get(&#x60;${base}/chunked-json&#x60;).end((error) =&#x3E; {\n  assert.ifError(error);\n  done();\n});</code></pre></dd>\n        <dt>should not emit error on aborted chunked json</dt>\n        <dd><pre><code>const request_ = request.get(&#x60;${base}/chunked-json&#x60;);\nrequest_.end((error) =&#x3E; {\n  assert.ifError(error);\n  done();\n});\nsetTimeout(() =&#x3E; {\n  request_.abort();\n}, 50);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>pipe on redirect</h1>\n      <dl>\n        <dt>should follow Location</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nconst redirects = [];\nconst request_ = request\n  .get(base)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .connect({\n    inapplicable: &#x27;should be ignored&#x27;\n  });\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  redirects.should.eql([&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;]);\n  fs.readFileSync(destinationPath, &#x27;utf8&#x27;).should.eql(&#x27;first movie page&#x27;);\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request pipe</h1>\n      <dl>\n        <dt>should act as a writable stream</dt>\n        <dd><pre><code>const request_ = request.post(base);\nconst stream = fs.createReadStream(&#x27;test/node/fixtures/user.json&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});\nstream.pipe(request_);</code></pre></dd>\n        <dt>end() stops piping</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nrequest.get(base).end((error, res) =&#x3E; {\n  try {\n    res.pipe(stream);\n    return done(new Error(&#x27;Did not prevent nonsense pipe&#x27;));\n  } catch {\n    /* expected error */\n  }\n  done();\n});</code></pre></dd>\n        <dt>should act as a readable stream</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nconst request_ = request.get(base);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.status.should.eql(200);\n  responseCalled = true;\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n    name: &#x27;tobi&#x27;\n  });\n  responseCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n        <dt>should follow redirects</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nconst request_ = request.get(base + &#x27;/redirect&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.status.should.eql(200);\n  responseCalled = true;\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n    name: &#x27;tobi&#x27;\n  });\n  responseCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n        <dt>should not throw on bad redirects</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nlet errorCalled = false;\nconst request_ = request.get(base + &#x27;/badRedirectNoLocation&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  responseCalled = true;\n});\nrequest_.on(&#x27;error&#x27;, (error) =&#x3E; {\n  error.message.should.eql(&#x27;No location header for redirect&#x27;);\n  errorCalled = true;\n  stream.end();\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  responseCalled.should.be.false();\n  errorCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.query(String)</h1>\n      <dl>\n        <dt>should support passing in a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work with url query-string and string for query</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/?name=tobi&#x60;)\n  .query(&#x27;age=2%20&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, age: &#x27;2 &#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should support compound elements in a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x26;age=2&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work when called multiple times with a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .query(&#x27;age=2%F6&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2%F6&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work with normal &#x60;query&#x60; object and query string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .query({ age: &#x27;2&#x27; })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should not encode raw backticks, but leave encoded ones as is</dt>\n        <dd><pre><code>return Promise.all([\n  request\n    .get(&#x60;${base}/raw-query&#x60;)\n    .query(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;)\n    .then((res) =&#x3E; {\n      res.text.should.eql(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;);\n    }),\n  request.get(base + &#x27;/raw-query?&#x60;age%60&#x60;=2%60&#x60;&#x27;).then((res) =&#x3E; {\n    res.text.should.eql(&#x27;&#x60;age%60&#x60;=2%60&#x60;&#x27;);\n  }),\n  request\n    .get(&#x60;${base}/raw-query&#x60;)\n    .query(&#x27;name=&#x60;t%60bi&#x60;&#x27;)\n    .query(&#x27;age&#x60;=2&#x27;)\n    .then((res) =&#x3E; {\n      res.text.should.eql(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;);\n    })\n]);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.query(Object)</h1>\n      <dl>\n        <dt>should construct the query-string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query({ name: &#x27;tobi&#x27; })\n  .query({ order: &#x27;asc&#x27; })\n  .query({ limit: [&#x27;1&#x27;, &#x27;2&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27;, limit: [&#x27;1&#x27;, &#x27;2&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>should encode raw backticks</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/raw-query&#x60;)\n  .query({ name: &#x27;&#x60;tobi&#x60;&#x27; })\n  .query({ &#x27;orde%60r&#x27;: null })\n  .query({ &#x27;&#x60;limit&#x60;&#x27;: [&#x27;%602&#x60;&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.text.should.eql(&#x27;name=%60tobi%60&#x26;orde%2560r&#x26;%60limit%60=%25602%60&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should not error on dates</dt>\n        <dd><pre><code>const date = new Date(0);\nrequest\n  .del(base)\n  .query({ at: date })\n  .end((error, res) =&#x3E; {\n    assert.equal(date.toISOString(), res.body.at);\n    done();\n  });</code></pre></dd>\n        <dt>should work after setting header fields</dt>\n        <dd><pre><code>request\n  .del(base)\n  .set(&#x27;Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;Bar&#x27;, &#x27;baz&#x27;)\n  .query({ name: &#x27;tobi&#x27; })\n  .query({ order: &#x27;asc&#x27; })\n  .query({ limit: [&#x27;1&#x27;, &#x27;2&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27;, limit: [&#x27;1&#x27;, &#x27;2&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>should append to the original query-string</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/?name=tobi&#x60;)\n  .query({ order: &#x27;asc&#x27; })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should retain the original query-string</dt>\n        <dd><pre><code>request.del(&#x60;${base}/?name=tobi&#x60;).end((error, res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});</code></pre></dd>\n        <dt>should keep only keys with null querystring values</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/url&#x60;)\n  .query({ nil: null })\n  .end((error, res) =&#x3E; {\n    res.text.should.equal(&#x27;/url?nil&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>query-string should be sent on pipe</dt>\n        <dd><pre><code>this.timeout(15_000);\nconst request_ = request.put(&#x60;${base}/?name=tobi&#x60;);\nconst stream = fs.createReadStream(&#x27;test/node/fixtures/user.json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});\nrequest_.on(&#x27;error&#x27;, (err) =&#x3E; {\n  done(err);\n});\nstream.on(&#x27;error&#x27;, function (err) {\n  done(err);\n});\nstream.pipe(request_);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.get</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on 301 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-301&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 302 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-302&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-303&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-307&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-308&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.post</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on 301 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-301&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 302 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-302&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-303&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307 redirect</h1>\n          <dl>\n            <dt>should follow Location with a POST request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-307&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;POST&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308 redirect</h1>\n          <dl>\n            <dt>should follow Location with a POST request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-308&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;POST&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on redirect</h1>\n          <dl>\n            <dt>should merge cookies if agent is used</dt>\n            <dd><pre><code>request\n  .agent()\n  .get(&#x60;${base}/cookie-redirect&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;orig=1; replaced=not&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(/orig=1/.test(res.text), &#x27;orig=1/.test&#x27;);\n      assert(/replaced=yes/.test(res.text), &#x27;replaced=yes/.test&#x27;);\n      assert(/from-redir=1/.test(res.text), &#x27;from-redir=1&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should not merge cookies if agent is not used</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/cookie-redirect&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;orig=1; replaced=not&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(/orig=1/.test(res.text), &#x27;/orig=1&#x27;);\n      assert(/replaced=not/.test(res.text), &#x27;/replaced=not&#x27;);\n      assert(!/replaced=yes/.test(res.text), &#x27;!/replaced=yes&#x27;);\n      assert(!/from-redir/.test(res.text), &#x27;!/from-redir&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should have previously set cookie for subsquent requests when agent is used</dt>\n            <dd><pre><code>const agent = request.agent();\nagent.get(&#x60;${base}/set-cookie&#x60;).end((error) =&#x3E; {\n  assert.ifError(error);\n  agent\n    .get(&#x60;${base}/show-cookies&#x60;)\n    .set({ Cookie: &#x27;orig=1&#x27; })\n    .end((error, res) =&#x3E; {\n      try {\n        assert.ifError(error);\n        assert(/orig=1/.test(res.text), &#x27;orig=1/.test&#x27;);\n        assert(/persist=123/.test(res.text), &#x27;persist=123&#x27;);\n        done();\n      } catch (err) {\n        done(err);\n      }\n    });\n});</code></pre></dd>\n            <dt>should follow Location</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .get(base)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n      redirects.should.eql(array);\n      res.text.should.equal(&#x27;first movie page&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should follow Location with IP override</dt>\n            <dd><pre><code>const redirects = [];\nconst url = URL.parse(base);\nreturn request\n  .get(&#x60;http://redir.example.com:${url.port || &#x27;80&#x27;}${url.pathname}&#x60;)\n  .connect({\n    &#x27;*&#x27;: url.hostname\n  })\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n    redirects.should.eql(array);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>should follow Location with IP:port override</dt>\n            <dd><pre><code>const redirects = [];\nconst url = URL.parse(base);\nreturn request\n  .get(&#x60;http://redir.example.com:9999${url.pathname}&#x60;)\n  .connect({\n    &#x27;*&#x27;: { host: url.hostname, port: url.port || 80 }\n  })\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n    redirects.should.eql(array);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>should not follow on HEAD by default</dt>\n            <dd><pre><code>const redirects = [];\nreturn request\n  .head(base)\n  .ok(() =&#x3E; true)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([]);\n    res.status.should.equal(302);\n  });</code></pre></dd>\n            <dt>should follow on HEAD when redirects are set</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .head(base)\n  .redirects(10)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;);\n      redirects.should.eql(array);\n      assert(!res.text);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should remove Content-* fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/header&#x60;)\n  .type(&#x27;txt&#x27;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;X-Bar&#x27;, &#x27;baz&#x27;)\n  .send(&#x27;hey&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      res.body.should.have.property(&#x27;x-bar&#x27;, &#x27;baz&#x27;);\n      res.body.should.not.have.property(&#x27;content-type&#x27;);\n      res.body.should.not.have.property(&#x27;content-length&#x27;);\n      res.body.should.not.have.property(&#x27;transfer-encoding&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should retain cookies</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/header&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;foo=bar;&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;cookie&#x27;, &#x27;foo=bar;&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should not resend query parameters</dt>\n            <dd><pre><code>const redirects = [];\nconst query = [];\nrequest\n  .get(&#x60;${base}/?foo=bar&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    query.push(res.headers.query);\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;);\n      redirects.should.eql(array);\n      res.text.should.equal(&#x27;first movie page&#x27;);\n      query.should.eql([&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, &#x27;{}&#x27;, &#x27;{}&#x27;]);\n      res.headers.query.should.eql(&#x27;{}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should handle no location header</dt>\n            <dd><pre><code>request.get(&#x60;${base}/bad-redirect&#x60;).end((error, res) =&#x3E; {\n  try {\n    error.message.should.equal(&#x27;No location header for redirect&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when relative</h1>\n              <dl>\n                <dt>should redirect to a sibling path</dt>\n                <dd><pre><code>const redirects = [];\nrequest\n  .get(&#x60;${base}/relative&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      redirects.should.eql([&#x27;tobi&#x27;]);\n      res.text.should.equal(&#x27;tobi&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n                <dt>should redirect to a parent path</dt>\n                <dd><pre><code>const redirects = [];\nrequest\n  .get(&#x60;${base}/relative/sub&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      redirects.should.eql([&#x27;../tobi&#x27;]);\n      res.text.should.equal(&#x27;tobi&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.redirects(n)</h1>\n          <dl>\n            <dt>should alter the default number of redirects to follow</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .get(base)\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      assert(res.redirect, &#x27;res.redirect&#x27;);\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;);\n      redirects.should.eql(array);\n      res.text.should.match(/Moved Temporarily|Found/);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on POST</h1>\n          <dl>\n            <dt>should redirect as GET</dt>\n            <dd><pre><code>const redirects = [];\nreturn request\n  .post(&#x60;${base}/movie&#x60;)\n  .send({ name: &#x27;Tobi&#x27; })\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([&#x27;/movies/all/0&#x27;]);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>using multipart/form-data should redirect as GET</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .post(&#x60;${base}/movie&#x60;)\n  .type(&#x27;form&#x27;)\n  .field(&#x27;name&#x27;, &#x27;Tobi&#x27;)\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([&#x27;/movies/all/0&#x27;]);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>response</h1>\n      <dl>\n        <dt>should act as a readable stream</dt>\n        <dd><pre><code>const request_ = request.get(base).buffer(false);\nrequest_.end((error, res) =&#x3E; {\n  if (error) return done(error);\n  let trackEndEvent = 0;\n  let trackCloseEvent = 0;\n  res.on(&#x27;end&#x27;, () =&#x3E; {\n    trackEndEvent++;\n    trackEndEvent.should.equal(1);\n    if (!process.env.HTTP2_TEST) {\n      trackCloseEvent.should.equal(0); // close should not have been called\n    }\n    done();\n  });\n  res.on(&#x27;close&#x27;, () =&#x3E; {\n    trackCloseEvent++;\n  });\n  setTimeout(() =&#x3E; {\n    (() =&#x3E; {\n      res.pause();\n    }).should.not.throw();\n    (() =&#x3E; {\n      res.resume();\n    }).should.not.throw();\n    (() =&#x3E; {\n      res.destroy();\n    }).should.not.throw();\n  }, 50);\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.serialize(fn)</h1>\n      <dl>\n        <dt>should take precedence over default parsers</dt>\n        <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .send({ foo: 123 })\n  .serialize(() =&#x3E; &#x27;{&#x22;bar&#x22;:456}&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(&#x27;{&#x22;bar&#x22;:456}&#x27;, res.text);\n    assert.equal(456, res.body.bar);\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.get().set()</h1>\n      <dl>\n        <dt>should set host header after get()</dt>\n        <dd><pre><code>app.get(&#x27;/&#x27;, (request_, res) =&#x3E; {\n  assert.equal(request_.hostname, &#x27;example.com&#x27;);\n  res.end();\n});\nserver = http.createServer(app);\nserver.listen(0, function listening() {\n  request\n    .get(&#x60;http://localhost:${server.address().port}&#x60;)\n    .set(&#x27;host&#x27;, &#x27;example.com&#x27;)\n    .then(() =&#x3E; {\n      return request\n        .get(&#x60;http://example.com:${server.address().port}&#x60;)\n        .connect({\n          &#x27;example.com&#x27;: &#x27;localhost&#x27;,\n          &#x27;*&#x27;: &#x27;fail&#x27;\n        });\n    })\n    .then(() =&#x3E; done(), done);\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.toError()</h1>\n      <dl>\n        <dt>should return an Error</dt>\n        <dd><pre><code>request.get(base).end((err, res) =&#x3E; {\n  const error = res.toError();\n  assert.equal(error.status, 400);\n  assert.equal(error.method, &#x27;GET&#x27;);\n  assert.equal(error.path, &#x27;/&#x27;);\n  assert.equal(error.message, &#x27;cannot GET / (400)&#x27;);\n  assert.equal(error.text, &#x27;invalid json&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[unix-sockets] http</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>request</h1>\n          <dl>\n            <dt>path: / (root)</dt>\n            <dd><pre><code>request.get(&#x60;${base}/&#x60;).end((error, res) =&#x3E; {\n  assert(res.ok);\n  assert.strictEqual(&#x27;root ok!&#x27;, res.text);\n  done();\n});</code></pre></dd>\n            <dt>path: /request/path</dt>\n            <dd><pre><code>request.get(&#x60;${base}/request/path&#x60;).end((error, res) =&#x3E; {\n  assert(res.ok);\n  assert.strictEqual(&#x27;request path ok!&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[unix-sockets] https</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>request</h1>\n          <dl>\n            <dt>path: / (root)</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/&#x60;)\n  .ca(cacert)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;root ok!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n            <dt>path: /request/path</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/request/path&#x60;)\n  .ca(cacert)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;request path ok!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.get()</h1>\n      <dl>\n        <dt>should not set a default user-agent</dt>\n        <dd><pre><code>request.get(&#x60;${base}/ua&#x60;).then((res) =&#x3E; {\n      assert(res.headers);\n      assert(!res.headers[&#x27;user-agent&#x27;]);\n    })</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.type(str)</h1>\n      <dl>\n        <dt>should return the mime type</dt>\n        <dd><pre><code>utils\n  .type(&#x27;application/json; charset=utf-8&#x27;)\n  .should.equal(&#x27;application/json&#x27;);\nutils.type(&#x27;application/json&#x27;).should.equal(&#x27;application/json&#x27;);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.params(str)</h1>\n      <dl>\n        <dt>should return the field parameters</dt>\n        <dd><pre><code>const object = utils.params(&#x27;application/json; charset=utf-8; foo  = bar&#x27;);\nobject.charset.should.equal(&#x27;utf-8&#x27;);\nobject.foo.should.equal(&#x27;bar&#x27;);\nutils.params(&#x27;application/json&#x27;).should.eql({});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.parseLinks(str)</h1>\n      <dl>\n        <dt>should parse links</dt>\n        <dd><pre><code>const string_ =\n  &#x27;&#x3C;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x3E;; rel=&#x22;next&#x22;, &#x3C;https://api.github.com/repos/visionmedia/mocha/issues?page=5&#x3E;; rel=&#x22;last&#x22;&#x27;;\nconst returnValue = utils.parseLinks(string_);\nreturnValue.next.should.equal(\n  &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x27;\n);\nreturnValue.last.should.equal(\n  &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=5&#x27;\n);</code></pre></dd>\n      </dl>\n    </section>\n-------------------|---------|----------|---------|---------|---------------------------------------\nFile               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                     \n-------------------|---------|----------|---------|---------|---------------------------------------\nAll files          |   85.79 |    79.93 |   78.06 |    86.6 |                                       \n src               |    92.5 |    83.83 |   91.83 |   93.84 |                                       \n  agent-base.js    |     100 |      100 |     100 |     100 |                                       \n  request-base.js  |   91.01 |     83.9 |   94.28 |   93.06 | ...21,262,316,501,525-533,579,757,768 \n  response-base.js |     100 |      100 |      75 |     100 |                                       \n  utils.js         |   92.85 |    71.42 |   85.71 |   91.66 | 94-98                                 \n src/node          |   82.28 |       78 |   68.42 |   82.94 |                                       \n  agent.js         |   89.79 |    66.66 |     100 |   88.63 | 39,43,47,51,101                       \n  http2wrapper.js  |    24.8 |     4.34 |       0 |   21.49 | ...76,180-181,185-186,190-191,196-198 \n  index.js         |   92.49 |    83.03 |   87.71 |    93.1 | ...,977,1142,1182-1186,1220-1221,1301 \n  response.js      |      90 |    83.33 |   55.55 |   89.79 | 78,86,94,120-121                      \n  unzip.js         |     100 |    92.85 |     100 |     100 | 47                                    \n src/node/parsers  |   97.61 |       75 |     100 |   97.61 |                                       \n  image.js         |     100 |      100 |     100 |     100 |                                       \n  index.js         |     100 |      100 |     100 |     100 |                                       \n  json.js          |     100 |       75 |     100 |     100 | 15                                    \n  text.js          |     100 |      100 |     100 |     100 |                                       \n  urlencoded.js    |      90 |      100 |     100 |      90 | 17                                    \n-------------------|---------|----------|---------|---------|---------------------------------------\ntest on node with http2\ntest on plain node\n    <section class=\"suite\">\n      <h1>Agent</h1>\n      <dl>\n        <dt>should remember defaults</dt>\n        <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nlet called = 0;\nlet event_called = 0;\nconst agent = request\n  .agent()\n  .accept(&#x27;json&#x27;)\n  .use(() =&#x3E; {\n    called++;\n  })\n  .once(&#x27;request&#x27;, () =&#x3E; {\n    event_called++;\n  })\n  .query({ hello: &#x27;world&#x27; })\n  .set(&#x27;X-test&#x27;, &#x27;testing&#x27;);\nassert.equal(0, called);\nassert.equal(0, event_called);\nreturn agent\n  .get(&#x60;${base}/echo&#x60;)\n  .then((res) =&#x3E; {\n    assert.equal(1, called);\n    assert.equal(1, event_called);\n    assert.equal(&#x27;application/json&#x27;, res.headers.accept);\n    assert.equal(&#x27;testing&#x27;, res.headers[&#x27;x-test&#x27;]);\n    return agent.get(&#x60;${base}/querystring&#x60;);\n  })\n  .then((res) =&#x3E; {\n    assert.equal(2, called);\n    assert.equal(2, event_called);\n    assert.deepEqual({ hello: &#x27;world&#x27; }, res.body);\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>res.statusCode</h1>\n          <dl>\n            <dt>should set statusCode</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.strictEqual(res.statusCode, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>should allow the send shorthand</h1>\n          <dl>\n            <dt>with callback in the method call</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  assert.equal(res.status, 200);\n  done();\n});</code></pre></dd>\n            <dt>with data in the method call</dt>\n            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }).end((error, res) =&#x3E; {\n  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);\n  done();\n});</code></pre></dd>\n            <dt>with callback and data in the method call</dt>\n            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }, (error, res) =&#x3E; {\n  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with a callback</h1>\n          <dl>\n            <dt>should invoke .end()</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(res.status, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.end()</h1>\n          <dl>\n            <dt>should issue a request</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(res.status, 200);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n            <dt>is optional with a promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/login&#x60;)\n  .then((res) =&#x3E; res.status)\n  .then()\n  .then((status) =&#x3E; {\n    assert.equal(200, status, &#x27;Real promises pass results through&#x27;);\n  });</code></pre></dd>\n            <dt>called only once with a promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nconst request_ = request.get(&#x60;${uri}/unique&#x60;);\nreturn Promise.all([request_, request_, request_]).then((results) =&#x3E; {\n  for (const item of results) {\n    assert.deepEqual(\n      item.body,\n      results[0].body,\n      &#x27;It should keep returning the same result after being called once&#x27;\n    );\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.error</h1>\n          <dl>\n            <dt>ok</dt>\n            <dd><pre><code>let calledErrorEvent = false;\nlet calledOKHandler = false;\nrequest\n  .get(&#x60;${uri}/error&#x60;)\n  .ok((res) =&#x3E; {\n    assert.strictEqual(500, res.status);\n    calledOKHandler = true;\n    return true;\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    calledErrorEvent = true;\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.strictEqual(res.status, 500);\n      assert(!calledErrorEvent);\n      assert(calledOKHandler);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should be an Error object</dt>\n            <dd><pre><code>let calledErrorEvent = false;\nrequest\n  .get(&#x60;${uri}/error&#x60;)\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    assert.strictEqual(error.status, 500);\n    calledErrorEvent = true;\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      if (NODE) {\n        res.error.message.should.equal(&#x27;cannot GET /error (500)&#x27;);\n      } else {\n        res.error.message.should.equal(&#x60;cannot GET ${uri}/error (500)&#x60;);\n      }\n      assert.strictEqual(res.error.status, 500);\n      assert(error, &#x27;should have an error for 500&#x27;);\n      assert.equal(error.message, &#x27;Internal Server Error&#x27;);\n      assert(calledErrorEvent);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>with .then() promise</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request.get(&#x60;${uri}/error&#x60;).then(\n  () =&#x3E; {\n    assert.fail();\n  },\n  (err) =&#x3E; {\n    assert.equal(err.message, &#x27;Internal Server Error&#x27;);\n  }\n);</code></pre></dd>\n            <dt>with .ok() returning false</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; false)\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;OK&#x27;);\n    }\n  );</code></pre></dd>\n            <dt>with .ok() throwing an Error</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; {\n    throw new Error(&#x27;boom&#x27;);\n  })\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(200, err.status);\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;boom&#x27;);\n    }\n  );</code></pre></dd>\n            <dt>with .ok() throwing an Error with status</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return;\n}\nreturn request\n  .get(&#x60;${uri}/echo&#x60;)\n  .ok(() =&#x3E; {\n    const err = new Error(&#x27;boom&#x27;);\n    err.status = 404;\n    throw err;\n  })\n  .then(\n    () =&#x3E; {\n      assert.fail();\n    },\n    (err) =&#x3E; {\n      assert.equal(404, err.status);\n      assert.equal(200, err.response.status);\n      assert.equal(err.message, &#x27;boom&#x27;);\n    }\n  );</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.header</h1>\n          <dl>\n            <dt>should be an object</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>set headers</h1>\n          <dl>\n            <dt>should only set headers for ownProperties of header</dt>\n            <dd><pre><code>try {\n  request\n    .get(&#x60;${uri}/echo-headers&#x60;)\n    .set(&#x27;valid&#x27;, &#x27;ok&#x27;)\n    .end((error, res) =&#x3E; {\n      if (\n        !error &#x26;&#x26;\n        res.body &#x26;&#x26;\n        res.body.valid &#x26;&#x26;\n        !res.body.hasOwnProperty(&#x27;invalid&#x27;)\n      ) {\n        return done();\n      }\n      done(error || new Error(&#x27;fail&#x27;));\n    });\n} catch (err) {\n  done(err);\n}</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.charset</h1>\n          <dl>\n            <dt>should be set when present</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    res.charset.should.equal(&#x27;utf-8&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.statusType</h1>\n          <dl>\n            <dt>should provide the first digit</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(!error, &#x27;should not have an error for success responses&#x27;);\n    assert.equal(200, res.status);\n    assert.equal(2, res.statusType);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.type</h1>\n          <dl>\n            <dt>should provide the mime-type void of params</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {\n  try {\n    res.type.should.equal(&#x27;text/html&#x27;);\n    res.charset.should.equal(&#x27;utf-8&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.set(field, val)</h1>\n          <dl>\n            <dt>should set the header field</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;X-Bar&#x27;, &#x27;baz&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);\n      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.set(obj)</h1>\n          <dl>\n            <dt>should set the header fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set({ &#x27;X-Foo&#x27;: &#x27;bar&#x27;, &#x27;X-Bar&#x27;: &#x27;baz&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);\n      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.type(str)</h1>\n          <dl>\n            <dt>should set the Content-Type</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;text/x-foo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/x-foo&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;json&#x22;</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;{&#x22;a&#x22;: 1}&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;html&#x22;</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;html&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/html&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.accept(str)</h1>\n          <dl>\n            <dt>should set Accept</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;text/x-foo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;text/x-foo&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;json&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;application/json&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;xml&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      // Mime module keeps changing this :(\n      assert(\n        res.header.accept == &#x27;application/xml&#x27; ||\n          res.header.accept == &#x27;text/xml&#x27;\n      );\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should map &#x22;html&#x22;</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/echo&#x60;)\n  .accept(&#x27;html&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.header.accept.should.equal(&#x27;text/html&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.send(str)</h1>\n          <dl>\n            <dt>should write the string</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.send(Object)</h1>\n          <dl>\n            <dt>should default to json</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when called several times</h1>\n              <dl>\n                <dt>should merge the objects</dt>\n                <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .send({ age: 1 })\n  .end((error, res) =&#x3E; {\n    try {\n      res.should.be.json();\n      if (NODE) {\n        res.buffered.should.be.true();\n      }\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.end(fn)</h1>\n          <dl>\n            <dt>should check arity</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should emit request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;);\nrequest_.on(&#x27;request&#x27;, (request) =&#x3E; {\n  assert.equal(request_, request);\n  done();\n});\nrequest_.end();</code></pre></dd>\n            <dt>should emit response</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .on(&#x27;response&#x27;, (res) =&#x3E; {\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.then(fulfill, reject)</h1>\n          <dl>\n            <dt>should support successful fulfills with .then(fulfill)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .then((res) =&#x3E; {\n    res.type.should.equal(&#x27;application/json&#x27;);\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should reject an error with .then(null, reject)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest.get(&#x60;${uri}/error&#x60;).then(null, (err) =&#x3E; {\n  assert.equal(err.status, 500);\n  assert.equal(err.response.text, &#x27;boom&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.catch(reject)</h1>\n          <dl>\n            <dt>should reject an error with .catch(reject)</dt>\n            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {\n  return done();\n}\nrequest.get(&#x60;${uri}/error&#x60;).catch((err) =&#x3E; {\n  assert.equal(err.status, 500);\n  assert.equal(err.response.text, &#x27;boom&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.abort()</h1>\n          <dl>\n            <dt>should abort the request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\nrequest_.on(&#x27;error&#x27;, (error) =&#x3E; {\n  done(error);\n});\nrequest_.on(&#x27;abort&#x27;, done);\nsetTimeout(() =&#x3E; {\n  request_.abort();\n}, 500);</code></pre></dd>\n            <dt>should abort the promise</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nsetTimeout(() =&#x3E; {\n  request_.abort();\n}, 10);\nreturn request_.then(\n  () =&#x3E; {\n    assert.fail(&#x27;should not complete the request&#x27;);\n  },\n  (err) =&#x3E; {\n    assert.equal(&#x27;ABORTED&#x27;, err.code);\n  }\n);</code></pre></dd>\n            <dt>should allow chaining .abort() several times</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\n// This also verifies only a single &#x27;done&#x27; event is emitted\nrequest_.on(&#x27;abort&#x27;, done);\nsetTimeout(() =&#x3E; {\n  request_.abort().abort().abort();\n}, 1000);</code></pre></dd>\n            <dt>should not allow abort then end</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/delay/3000&#x60;)\n  .abort()\n  .end((error, res) =&#x3E; {\n    done(error ? undefined : new Error(&#x27;Expected abort error&#x27;));\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.toJSON()</h1>\n          <dl>\n            <dt>should describe the request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;).send({ foo: &#x27;baz&#x27; });\nrequest_.end((error, res) =&#x3E; {\n  try {\n    const json = request_.toJSON();\n    assert.equal(&#x27;POST&#x27;, json.method);\n    assert(/\\/echo$/.test(json.url));\n    assert.equal(&#x27;baz&#x27;, json.data.foo);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.options()</h1>\n          <dl>\n            <dt>should allow request body</dt>\n            <dd><pre><code>request\n  .options(&#x60;${uri}/options/echo/body&#x60;)\n  .send({ foo: &#x27;baz&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(error, null);\n      assert.strictEqual(res.body.foo, &#x27;baz&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.sortQuery()</h1>\n          <dl>\n            <dt>nop with no querystring</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .sortQuery()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should sort the request querystring</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?order=desc&#x26;search=Manny&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should allow disabling sorting</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery() // take default of true\n  .sortQuery(false) // override it in later call\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?search=Manny&#x26;order=desc&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should sort the request querystring using customized function</dt>\n            <dd><pre><code>request\n  .get(&#x60;${uri}/url&#x60;)\n  .query(&#x27;name=Nick&#x27;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .sortQuery((a, b) =&#x3E; a.length - b.length)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(res.text, &#x27;/url?name=Nick&#x26;order=desc&#x26;search=Manny&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.set(&#x22;Content-Type&#x22;, contentType)</h1>\n      <dl>\n        <dt>should work with just the contentType component</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error) =&#x3E; {\n    assert(!error);\n    done();\n  });</code></pre></dd>\n        <dt>should work with the charset component</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json; charset=utf-8&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error) =&#x3E; {\n    assert(!error);\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(Object) as &#x22;form&#x22;</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>with req.type() set to form</h1>\n          <dl>\n            <dt>should send x-www-form-urlencoded data</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;form&#x27;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.text.should.equal(&#x27;name=tobi&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>when called several times</h1>\n          <dl>\n            <dt>should merge the objects</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;form&#x27;)\n  .send({ name: { first: &#x27;tobi&#x27;, last: &#x27;holowaychuk&#x27; } })\n  .send({ age: &#x27;1&#x27; })\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.text.should.equal(\n      &#x27;name%5Bfirst%5D=tobi&#x26;name%5Blast%5D=holowaychuk&#x26;age=1&#x27;\n    );\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.attach</h1>\n      <dl>\n        <dt>ignores null file</dt>\n        <dd><pre><code>request\n  .post(&#x27;/echo&#x27;)\n  .attach(&#x27;image&#x27;, null)\n  .end((error, res) =&#x3E; {\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.field</h1>\n      <dl>\n        <dt>allow bools</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field(&#x27;bools&#x27;, true)\n  .field(&#x27;strings&#x27;, &#x27;true&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>allow objects</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field({ bools: true, strings: &#x27;true&#x27; })\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>works with arrays in objects</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field({ numbers: [1, 2, 3] })\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { numbers: [&#x27;1&#x27;, &#x27;2&#x27;, &#x27;3&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>works with arrays</dt>\n        <dd><pre><code>if (!formDataSupported) {\n  return done();\n}\nrequest\n  .post(&#x60;${base}/formecho&#x60;)\n  .field(&#x27;letters&#x27;, [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;])\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.deepStrictEqual(res.body, { letters: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>throw when empty</dt>\n        <dd><pre><code>should.throws(() =&#x3E; {\n  request.post(&#x60;${base}/echo&#x60;).field();\n}, /name/);\nshould.throws(() =&#x3E; {\n  request.post(&#x60;${base}/echo&#x60;).field(&#x27;name&#x27;);\n}, /val/);</code></pre></dd>\n        <dt>cannot be mixed with send()</dt>\n        <dd><pre><code>assert.throws(() =&#x3E; {\n  request.post(&#x27;/echo&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;).send(&#x27;hi&#x27;);\n});\nassert.throws(() =&#x3E; {\n  request.post(&#x27;/echo&#x27;).send(&#x27;hi&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;);\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(Object) as &#x22;json&#x22;</h1>\n      <dl>\n        <dt>should default to json</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with arrays</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send([1, 2, 3])\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;[1,2,3]&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with value null</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;null&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    assert.strictEqual(res.body, null);\n    done();\n  });</code></pre></dd>\n        <dt>should work with value false</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;false&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.body.should.equal(false);\n    done();\n  });</code></pre></dd>\n        <dt>should work with empty string value</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .type(&#x27;json&#x27;)\n  .send(&#x27;&#x22;&#x22;&#x27;)\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.body.should.equal(&#x27;&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should work with vendor MIME type</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/vnd.example+json&#x27;)\n  .send({ name: &#x27;vendor&#x27; })\n  .end((error, res) =&#x3E; {\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;vendor&#x22;}&#x27;);\n    ({ name: &#x27;vendor&#x27; }.should.eql(res.body));\n    done();\n  });</code></pre></dd>\n        <section class=\"suite\">\n          <h1>when called several times</h1>\n          <dl>\n            <dt>should merge the objects</dt>\n            <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send({ name: &#x27;tobi&#x27; })\n  .send({ age: 1 })\n  .end((error, res) =&#x3E; {\n    res.should.be.json();\n    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);\n    ({ name: &#x27;tobi&#x27;, age: 1 }.should.eql(res.body));\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>application/json</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/json&#x60;).end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;manny&#x22;}&#x27;);\n  res.body.should.eql({ name: &#x27;manny&#x27; });\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>Invalid JSON response</h1>\n          <dl>\n            <dt>should return the raw response</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/invalid-json&#x60;).end((error, res) =&#x3E; {\n  assert.deepEqual(\n    error.rawResponse,\n    &#x22;)]}&#x27;, {&#x27;header&#x27;:{&#x27;code&#x27;:200,&#x27;text&#x27;:&#x27;OK&#x27;,&#x27;version&#x27;:&#x27;1.0&#x27;},&#x27;data&#x27;:&#x27;some data&#x27;}&#x22;\n  );\n  done();\n});</code></pre></dd>\n            <dt>should return the http status code</dt>\n            <dd><pre><code>request.get(&#x60;${uri}/invalid-json-forbidden&#x60;).end((error, res) =&#x3E; {\n  assert.equal(error.statusCode, 403);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on redirect</h1>\n          <dl>\n            <dt>should retain header fields</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/header&#x60;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should preserve timeout across redirects</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/movies/random&#x60;)\n  .timeout(250)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error instanceof Error, &#x27;expected an error&#x27;);\n      error.should.have.property(&#x27;timeout&#x27;, 250);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should successfully redirect after retry on error</dt>\n            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();\nrequest\n  .get(&#x60;${base}/error/redirect/${id}&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(res.text, &#x27;first movie page&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should preserve retries across redirects</dt>\n            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();\nrequest\n  .get(&#x60;${base}/error/redirect-error${id}&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n    assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>request\n  .put(&#x60;${base}/redirect-303&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=get&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>if (isMSIE) return done(); // IE9 broken\nrequest\n  .put(&#x60;${base}/redirect-307&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=put&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308</h1>\n          <dl>\n            <dt>should redirect with same method</dt>\n            <dd><pre><code>if (isMSIE) return done(); // IE9 broken\nrequest\n  .put(&#x60;${base}/redirect-308&#x60;)\n  .send({ msg: &#x27;hello&#x27; })\n  .redirects(1)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    res.headers.location.should.equal(&#x27;/reply-method&#x27;);\n  })\n  .end((error, res) =&#x3E; {\n    if (error) {\n      done(error);\n      return;\n    }\n    res.text.should.equal(&#x27;method=put&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <dt>Request inheritance</dt>\n        <dd><pre><code>assert(request.get(&#x60;${uri}/&#x60;) instanceof request.Request);</code></pre></dd>\n        <dt>request() simple GET without callback</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x27;test/test.request.js&#x27;).end();\nnext();</code></pre></dd>\n        <dt>request() simple GET</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(res.text, &#x27;res.text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() simple HEAD</dt>\n        <dd><pre><code>request.head(&#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);\n    assert(res.ok, &#x27;response should be ok&#x27;);\n    assert(!res.text, &#x27;res.text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 5xx</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/error&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(error.message, &#x27;Internal Server Error&#x27;);\n    assert(!res.ok, &#x27;response should not be ok&#x27;);\n    assert(res.error, &#x27;response should be an error&#x27;);\n    assert(!res.clientError, &#x27;response should not be a client error&#x27;);\n    assert(res.serverError, &#x27;response should be a server error&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 4xx</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(error.message, &#x27;Not Found&#x27;);\n    assert(!res.ok, &#x27;response should not be ok&#x27;);\n    assert(res.error, &#x27;response should be an error&#x27;);\n    assert(res.clientError, &#x27;response should be a client error&#x27;);\n    assert(!res.serverError, &#x27;response should not be a server error&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 404 Not Found</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.notFound, &#x27;response should be .notFound&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 400 Bad Request</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/bad-request&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.badRequest, &#x27;response should be .badRequest&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 401 Bad Request</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/unauthorized&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.unauthorized, &#x27;response should be .unauthorized&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 406 Not Acceptable</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/not-acceptable&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert(res.notAcceptable, &#x27;response should be .notAcceptable&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() GET 204 No Content</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.ifError(error);\n    assert(res.noContent, &#x27;response should be .noContent&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() DELETE 204 No Content</dt>\n        <dd><pre><code>request(&#x27;DELETE&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.ifError(error);\n    assert(res.noContent, &#x27;response should be .noContent&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() header parsing</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(&#x27;text/html; charset=utf-8&#x27;, res.header[&#x27;content-type&#x27;]);\n    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request() .status</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(404, res.status, &#x27;response .status&#x27;);\n    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>get()</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert(error);\n    assert.equal(404, res.status, &#x27;response .status&#x27;);\n    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>put()</dt>\n        <dd><pre><code>request.put(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;updated&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>put().send()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/user/13/body&#x60;)\n  .send({ user: &#x27;new&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;received new&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>post()</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;created&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>del()</dt>\n        <dd><pre><code>request.del(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>delete()</dt>\n        <dd><pre><code>request.delete(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>post() data</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/todo/item&#x60;)\n  .type(&#x27;application/octet-stream&#x27;)\n  .send(&#x27;tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .type()</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/user/12/pet&#x60;)\n  .type(&#x27;urlencoded&#x27;)\n  .send(&#x27;pet=tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .type() with alias</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/user/12/pet&#x60;)\n  .type(&#x27;application/x-www-form-urlencoded&#x27;)\n  .send(&#x27;pet=tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .get() with no data or callback</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/echo-header/content-type&#x60;);\nnext();</code></pre></dd>\n        <dt>request .send() with no data only</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/5/pet&#x60;).type(&#x27;urlencoded&#x27;).send(&#x27;pet=tobi&#x27;);\nnext();</code></pre></dd>\n        <dt>request .send() with callback only</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .set(&#x27;Accept&#x27;, &#x27;foo/bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;foo/bar&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with json</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/json&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with application/json</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;application/json&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/json&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with xml</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      // We can&#x27;t depend on mime module to be consistent with this\n      assert(res.text == &#x27;application/xml&#x27; || res.text == &#x27;text/xml&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .accept() with application/xml</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/echo-header/accept&#x60;)\n  .accept(&#x27;application/xml&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;application/xml&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .end()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .send()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .set()</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>request .set(object)</dt>\n        <dd><pre><code>request\n  .put(&#x60;${uri}/echo-header/content-type&#x60;)\n  .set({ &#x27;Content-Type&#x27;: &#x27;text/plain&#x27; })\n  .send(&#x27;wahoo&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;text/plain&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST urlencoded</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .type(&#x27;urlencoded&#x27;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .type(&#x27;json&#x27;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json array</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send([1, 2, 3])\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(\n        &#x27;application/json&#x27;,\n        res.header[&#x27;content-type&#x27;].split(&#x27;;&#x27;)[0]\n      );\n      assert.equal(&#x27;[1,2,3]&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json default</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .send({ name: &#x27;Manny&#x27;, species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json contentType charset</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/json; charset=UTF-8&#x27;)\n  .send({ data: [&#x27;data1&#x27;, &#x27;data2&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;{&#x22;data&#x22;:[&#x22;data1&#x22;,&#x22;data2&#x22;]}&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST json contentType vendor</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .set(&#x27;Content-Type&#x27;, &#x27;application/vnd.example+json&#x27;)\n  .send({ data: [&#x27;data1&#x27;, &#x27;data2&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;{&#x22;data&#x22;:[&#x22;data1&#x22;,&#x22;data2&#x22;]}&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST multiple .send() calls</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/pet&#x60;)\n  .send({ name: &#x27;Manny&#x27; })\n  .send({ species: &#x27;cat&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;added Manny the cat&#x27;, res.text);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST multiple .send() strings</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/echo&#x60;)\n  .send(&#x27;user[name]=tj&#x27;)\n  .send(&#x27;user[email]=tj@vision-media.ca&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(\n        &#x27;application/x-www-form-urlencoded&#x27;,\n        res.header[&#x27;content-type&#x27;].split(&#x27;;&#x27;)[0]\n      );\n      assert.equal(\n        res.text,\n        &#x27;user[name]=tj&#x26;user[email]=tj@vision-media.ca&#x27;\n      );\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>POST with no data</dt>\n        <dd><pre><code>request\n  .post(&#x60;${uri}/empty-body&#x60;)\n  .send()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.noContent, &#x27;response should be .noContent&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET .type</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/pets&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;application/json&#x27;, res.type);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET Content-Type params</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/text&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;utf-8&#x27;, res.charset);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET json</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/pets&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.deepEqual(res.body, [&#x27;tobi&#x27;, &#x27;loki&#x27;, &#x27;jane&#x27;]);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET json-seq</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/json-seq&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.deepEqual(res.text, &#x27;\\u001E{&#x22;id&#x22;:1}\\n\\u001E{&#x22;id&#x22;:2}\\n&#x27;);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET binary data</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/binary-data&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert.deepEqual(res.body, binData);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET x-www-form-urlencoded</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.deepEqual(res.body, { foo: &#x27;bar&#x27; });\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET shorthand</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/foo&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;foo=bar&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>POST shorthand</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/0/pet&#x60;, { pet: &#x27;tobi&#x27; }, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>POST shorthand without callback</dt>\n        <dd><pre><code>request.post(&#x60;${uri}/user/0/pet&#x60;, { pet: &#x27;tobi&#x27; }).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>GET querystring object with array</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ val: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { val: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object with array and primitives</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ array: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;], string: &#x27;foo&#x27;, number: 10 })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        array: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;],\n        string: &#x27;foo&#x27;,\n        number: 10\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object with two arrays</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ array1: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;], array2: [1, 2, 3] })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        array1: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;],\n        array2: [1, 2, 3]\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring object</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ search: &#x27;Manny&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { search: &#x27;Manny&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring append original</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring?search=Manny&#x60;)\n  .query({ range: &#x27;1..5&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { search: &#x27;Manny&#x27;, range: &#x27;1..5&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring multiple objects</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query({ search: &#x27;Manny&#x27; })\n  .query({ range: &#x27;1..5&#x27; })\n  .query({ order: &#x27;desc&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring with strings</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query(&#x27;range=1..5&#x27;)\n  .query(&#x27;order=desc&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET querystring with strings and objects</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/querystring&#x60;)\n  .query(&#x27;search=Manny&#x27;)\n  .query({ order: &#x27;desc&#x27;, range: &#x27;1..5&#x27; })\n  .end((error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, {\n        search: &#x27;Manny&#x27;,\n        range: &#x27;1..5&#x27;,\n        order: &#x27;desc&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  });</code></pre></dd>\n        <dt>GET shorthand payload goes to querystring</dt>\n        <dd><pre><code>request.get(\n  &#x60;${uri}/querystring&#x60;,\n  { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; },\n  (error, res) =&#x3E; {\n    try {\n      assert.deepEqual(res.body, { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  }\n);</code></pre></dd>\n        <dt>HEAD shorthand payload goes to querystring</dt>\n        <dd><pre><code>request.head(\n  &#x60;${uri}/querystring-in-header&#x60;,\n  { foo: &#x27;FOO&#x27;, bar: &#x27;BAR&#x27; },\n  (error, res) =&#x3E; {\n    try {\n      assert.deepEqual(JSON.parse(res.headers.query), {\n        foo: &#x27;FOO&#x27;,\n        bar: &#x27;BAR&#x27;\n      });\n      next();\n    } catch (err) {\n      next(err);\n    }\n  }\n);</code></pre></dd>\n        <dt>request(method, url)</dt>\n        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request(url)</dt>\n        <dd><pre><code>request(&#x60;${uri}/foo&#x60;).end((error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request(url, fn)</dt>\n        <dd><pre><code>request(&#x60;${uri}/foo&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.equal(&#x27;bar&#x27;, res.body.foo);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.timeout(ms)</dt>\n        <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;).timeout(1000);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(error, &#x27;error missing&#x27;);\n    assert.equal(1000, error.timeout, &#x27;err.timeout missing&#x27;);\n    assert.equal(\n      &#x27;Timeout of 1000ms exceeded&#x27;,\n      error.message,\n      &#x27;err.message incorrect&#x27;\n    );\n    assert.equal(null, res);\n    assert(request_.timedout, true);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.timeout(ms) with redirect</dt>\n        <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/const&#x60;).timeout(1000);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(error, &#x27;error missing&#x27;);\n    assert.equal(1000, error.timeout, &#x27;err.timeout missing&#x27;);\n    assert.equal(\n      &#x27;Timeout of 1000ms exceeded&#x27;,\n      error.message,\n      &#x27;err.message incorrect&#x27;\n    );\n    assert.equal(null, res);\n    assert(request_.timedout, true);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>request event</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/foo&#x60;)\n  .on(&#x27;request&#x27;, (request_) =&#x3E; {\n    try {\n      assert.equal(&#x60;${uri}/foo&#x60;, request_.url);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  })\n  .end();</code></pre></dd>\n        <dt>response event</dt>\n        <dd><pre><code>request\n  .get(&#x60;${uri}/foo&#x60;)\n  .on(&#x27;response&#x27;, (res) =&#x3E; {\n    try {\n      assert.equal(&#x27;bar&#x27;, res.body.foo);\n      next();\n    } catch (err) {\n      next(err);\n    }\n  })\n  .end();</code></pre></dd>\n        <dt>response should set statusCode</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/ok&#x60;, (error, res) =&#x3E; {\n  try {\n    assert.strictEqual(res.statusCode, 200);\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n        <dt>req.toJSON()</dt>\n        <dd><pre><code>request.get(&#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {\n  try {\n    const index = (res.request || res.req).toJSON();\n    for (const property of [&#x27;url&#x27;, &#x27;method&#x27;, &#x27;data&#x27;, &#x27;headers&#x27;]) {\n      assert(index.hasOwnProperty(property));\n    }\n    next();\n  } catch (err) {\n    next(err);\n  }\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>.retry(count)</h1>\n      <dl>\n        <dt>should not retry if passed &#x22;0&#x22;</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(0)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry if passed an invalid number</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(-2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry if passed undefined</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(undefined)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(\n        undefined,\n        error.retries,\n        &#x27;expected an error without .retries&#x27;\n      );\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle server error after repeat attempt</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should retry if passed nothing</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry()\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(1, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should retry if passed &#x22;true&#x22;</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error&#x60;)\n  .retry(true)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(1, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server error</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error/ok/${uniqid()}&#x60;)\n  .query({ qs: &#x27;present&#x27; })\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert(res.text, &#x27;res.text&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle server timeout error after repeat attempt</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/delay/400&#x60;)\n  .timeout(200)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(\n        &#x27;number&#x27;,\n        typeof error.timeout,\n        &#x27;expected an error with .timeout&#x27;\n      );\n      assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server timeout</dt>\n        <dd><pre><code>const url = &#x60;/delay/1200/ok/${uniqid()}?built=in&#x60;;\nrequest\n  .get(base + url)\n  .query(&#x27;string=ified&#x27;)\n  .query({ json: &#x27;ed&#x27; })\n  .timeout(600)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert.equal(res.text, &#x60;ok = ${url}&#x26;string=ified&#x26;json=ed&#x60;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should handle successful request after repeat attempt from server timeout when using .then(fulfill, reject)</dt>\n        <dd><pre><code>const url = &#x60;/delay/1200/ok/${uniqid()}?built=in&#x60;;\nrequest\n  .get(base + url)\n  .query(&#x27;string=ified&#x27;)\n  .query({ json: &#x27;ed&#x27; })\n  .timeout(600)\n  .retry(1)\n  .then((res, error) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.ok, &#x27;response should be ok&#x27;);\n      assert.equal(res.text, &#x60;ok = ${url}&#x26;string=ified&#x26;json=ed&#x60;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should correctly abort a retry attempt</dt>\n        <dd><pre><code>let aborted = false;\nconst request_ = request.get(&#x60;${base}/delay/400&#x60;).timeout(200).retry(2);\nrequest_.end((error, res) =&#x3E; {\n  try {\n    assert(false, &#x27;should not complete the request&#x27;);\n  } catch (err) {\n    done(err);\n  }\n});\nrequest_.on(&#x27;abort&#x27;, () =&#x3E; {\n  aborted = true;\n});\nsetTimeout(() =&#x3E; {\n  request_.abort();\n  setTimeout(() =&#x3E; {\n    try {\n      assert(aborted, &#x27;should be aborted&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  }, 150);\n}, 150);</code></pre></dd>\n        <dt>should correctly retain header fields</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/error/ok/${uniqid()}&#x60;)\n  .query({ qs: &#x27;present&#x27; })\n  .retry(2)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should not retry on 4xx responses</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/bad-request&#x60;)\n  .retry(2)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(0, error.retries, &#x27;expected an error with 0 .retries&#x27;);\n      assert.equal(400, error.status, &#x27;expected an error status of 400&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should execute callback on retry if passed</dt>\n        <dd><pre><code>let callbackCallCount = 0;\nfunction retryCallback(request) {\n  callbackCallCount++;\n}\nrequest\n  .get(&#x60;${base}/error&#x60;)\n  .retry(2, retryCallback)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(error, &#x27;expected an error&#x27;);\n      assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);\n      assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);\n      assert.equal(\n        2,\n        callbackCallCount,\n        &#x27;expected the callback to be called on each retry&#x27;\n      );\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>.timeout(ms)</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>when timeout is exceeded</h1>\n          <dl>\n            <dt>should error</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should error in promise interface </dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout(150)\n  .catch((err) =&#x3E; {\n    assert(err, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof err.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, err.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should handle gzip timeout</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/zip&#x60;)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should handle buffer timeout</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/json&#x60;)\n  .buffer(true)\n  .timeout(150)\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should error on deadline</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ deadline: 150 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should support setting individual options</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ deadline: 10 })\n  .timeout({ response: 99_999 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    assert.equal(&#x27;ETIME&#x27;, error.errno);\n    done();\n  });</code></pre></dd>\n            <dt>should error on response</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/500&#x60;)\n  .timeout({ response: 150 })\n  .end((error, res) =&#x3E; {\n    assert(error, &#x27;expected an error&#x27;);\n    assert.equal(\n      &#x27;number&#x27;,\n      typeof error.timeout,\n      &#x27;expected an error with .timeout&#x27;\n    );\n    assert.equal(&#x27;ECONNABORTED&#x27;, error.code, &#x27;expected abort error code&#x27;);\n    assert.equal(&#x27;ETIMEDOUT&#x27;, error.errno);\n    done();\n  });</code></pre></dd>\n            <dt>should accept slow body with fast response</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/delay/slowbody&#x60;)\n  .timeout({ response: 1000 })\n  .on(&#x27;progress&#x27;, () =&#x3E; {\n    // This only makes the test faster without relying on arbitrary timeouts\n    request.get(&#x60;${base}/delay/slowbody/finish&#x60;).end();\n  })\n  .end(done);</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>use</h1>\n          <dl>\n            <dt>should use plugin success</dt>\n            <dd><pre><code>const now = &#x60;${Date.now()}&#x60;;\nfunction uuid(request_) {\n  request_.set(&#x27;X-UUID&#x27;, now);\n  return request_;\n}\nfunction prefix(request_) {\n  request_.url = uri + request_.url;\n  return request_;\n}\nrequest\n  .get(&#x27;/echo&#x27;)\n  .use(uuid)\n  .use(prefix)\n  .end((error, res) =&#x3E; {\n    assert.strictEqual(res.statusCode, 200);\n    assert.equal(res.get(&#x27;X-UUID&#x27;), now);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>subclass</h1>\n      <dl>\n        <dt>should be an instance of Request</dt>\n        <dd><pre><code>const request_ = request.get(&#x27;/&#x27;);\nassert(request_ instanceof request.Request);</code></pre></dd>\n        <dt>should use patched subclass</dt>\n        <dd><pre><code>assert(OriginalRequest);\nlet constructorCalled;\nlet sendCalled;\nfunction NewRequest(...args) {\n  constructorCalled = true;\n  OriginalRequest.apply(this, args);\n}\nNewRequest.prototype = Object.create(OriginalRequest.prototype);\nNewRequest.prototype.send = function () {\n  sendCalled = true;\n  return this;\n};\nrequest.Request = NewRequest;\nconst request_ = request.get(&#x27;/&#x27;).send();\nassert(constructorCalled);\nassert(sendCalled);\nassert(request_ instanceof NewRequest);\nassert(request_ instanceof OriginalRequest);</code></pre></dd>\n        <dt>should use patched subclass in agent too</dt>\n        <dd><pre><code>if (!request.agent) return; // Node-only\nfunction NewRequest(...args) {\n  OriginalRequest.apply(this, args);\n}\nNewRequest.prototype = Object.create(OriginalRequest.prototype);\nrequest.Request = NewRequest;\nconst request_ = request.agent().del(&#x27;/&#x27;);\nassert(request_ instanceof NewRequest);\nassert(request_ instanceof OriginalRequest);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>persistent agent</h1>\n          <dl>\n            <dt>should gain a session on POST</dt>\n            <dd><pre><code>agent3.post(&#x60;${base}/signin&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should start with empty session (set cookies)</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  should.exist(res.headers[&#x27;set-cookie&#x27;]);\n  done();\n});</code></pre></dd>\n            <dt>should gain a session (cookies already set)</dt>\n            <dd><pre><code>agent1.post(&#x60;${base}/signin&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should persist cookies across requests</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n      })</code></pre></dd>\n            <dt>should have the cookie set in the end callback</dt>\n            <dd><pre><code>agent4\n        .post(&#x60;${base}/setcookie&#x60;)\n        .then(() =&#x3E; agent4.get(&#x60;${base}/getcookie&#x60;))\n        .then((res) =&#x3E; {\n          res.should.have.status(200);\n          assert.strictEqual(res.text, &#x27;jar&#x27;);\n        })</code></pre></dd>\n            <dt>should not share cookies</dt>\n            <dd><pre><code>agent2.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  done();\n});</code></pre></dd>\n            <dt>should not lose cookies between agents</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n      })</code></pre></dd>\n            <dt>should be able to follow redirects</dt>\n            <dd><pre><code>agent1.get(base).then((res) =&#x3E; {\n        res.should.have.status(200);\n        res.text.should.containEql(&#x27;dashboard&#x27;);\n      })</code></pre></dd>\n            <dt>should be able to post redirects</dt>\n            <dd><pre><code>agent1\n        .post(&#x60;${base}/redirect&#x60;)\n        .send({ foo: &#x27;bar&#x27;, baz: &#x27;blaaah&#x27; })\n        .then((res) =&#x3E; {\n          res.should.have.status(200);\n          res.text.should.containEql(&#x27;simple&#x27;);\n          res.redirects.should.eql([&#x60;${base}/simple&#x60;]);\n        })</code></pre></dd>\n            <dt>should be able to limit redirects</dt>\n            <dd><pre><code>agent1\n  .get(base)\n  .redirects(0)\n  .end((error, res) =&#x3E; {\n    should.exist(error);\n    res.should.have.status(302);\n    res.redirects.should.eql([]);\n    res.header.location.should.equal(&#x27;/dashboard&#x27;);\n    done();\n  });</code></pre></dd>\n            <dt>should be able to create a new session (clear cookie)</dt>\n            <dd><pre><code>agent1.post(&#x60;${base}/signout&#x60;).then((res) =&#x3E; {\n        res.should.have.status(200);\n        should.exist(res.headers[&#x27;set-cookie&#x27;]);\n      })</code></pre></dd>\n            <dt>should regenerate with an empty session</dt>\n            <dd><pre><code>agent1.get(&#x60;${base}/dashboard&#x60;).end((error, res) =&#x3E; {\n  should.exist(error);\n  res.should.have.status(401);\n  should.not.exist(res.headers[&#x27;set-cookie&#x27;]);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Basic auth</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>when credentials are present in url</h1>\n          <dl>\n            <dt>should set Authorization</dt>\n            <dd><pre><code>const new_url = URL.parse(base);\nnew_url.auth = &#x27;tobi:learnboost&#x27;;\nnew_url.pathname = &#x27;/basic-auth&#x27;;\nrequest.get(URL.format(new_url)).end((error, res) =&#x3E; {\n  res.status.should.equal(200);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.auth(user, pass)</h1>\n          <dl>\n            <dt>should set Authorization</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/basic-auth&#x60;)\n  .auth(&#x27;tobi&#x27;, &#x27;learnboost&#x27;)\n  .end((error, res) =&#x3E; {\n    res.status.should.equal(200);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.auth(user + &#x22;:&#x22; + pass)</h1>\n          <dl>\n            <dt>should set authorization</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/basic-auth/again&#x60;)\n  .auth(&#x27;tobi&#x27;)\n  .end((error, res) =&#x3E; {\n    res.status.should.eql(200);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[node] request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>with an url</h1>\n          <dl>\n            <dt>should preserve the encoding of the url</dt>\n            <dd><pre><code>request.get(&#x60;${base}/url?a=(b%29&#x60;).end((error, res) =&#x3E; {\n  assert.equal(&#x27;/url?a=(b%29&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with an object</h1>\n          <dl>\n            <dt>should format the url</dt>\n            <dd><pre><code>request.get(url.parse(&#x60;${base}/login&#x60;)).then((res) =&#x3E; {\n        assert(res.ok);\n      })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>without a schema</h1>\n          <dl>\n            <dt>should default to http</dt>\n            <dd><pre><code>request.get(&#x60;${base}/login&#x60;).then((res) =&#x3E; {\n        assert.equal(res.status, 200);\n      })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.toJSON()</h1>\n          <dl>\n            <dt>should describe the response</dt>\n            <dd><pre><code>request\n        .post(&#x60;${base}/echo&#x60;)\n        .send({ foo: &#x27;baz&#x27; })\n        .then((res) =&#x3E; {\n          const object = res.toJSON();\n          assert.equal(&#x27;object&#x27;, typeof object.header);\n          assert.equal(&#x27;object&#x27;, typeof object.req);\n          assert.equal(200, object.status);\n          assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;baz&#x22;}&#x27;, object.text);\n        })</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>res.links</h1>\n          <dl>\n            <dt>should default to an empty object</dt>\n            <dd><pre><code>request.get(&#x60;${base}/login&#x60;).then((res) =&#x3E; {\n        res.links.should.eql({});\n      })</code></pre></dd>\n            <dt>should parse the Link header field</dt>\n            <dd><pre><code>request.get(&#x60;${base}/links&#x60;).end((error, res) =&#x3E; {\n  res.links.next.should.equal(\n    &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x27;\n  );\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.unset(field)</h1>\n          <dl>\n            <dt>should remove the header field</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .unset(&#x27;User-Agent&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.equal(void 0, res.header[&#x27;user-agent&#x27;]);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>case-insensitive</h1>\n          <dl>\n            <dt>should set/get header fields case-insensitively</dt>\n            <dd><pre><code>const r = request.post(&#x60;${base}/echo&#x60;);\nr.set(&#x27;MiXeD&#x27;, &#x27;helloes&#x27;);\nassert.strictEqual(r.get(&#x27;mixed&#x27;), &#x27;helloes&#x27;);</code></pre></dd>\n            <dt>should unset header fields case-insensitively</dt>\n            <dd><pre><code>const r = request.post(&#x60;${base}/echo&#x60;);\nr.set(&#x27;MiXeD&#x27;, &#x27;helloes&#x27;);\nr.unset(&#x27;MIXED&#x27;);\nassert.strictEqual(r.get(&#x27;mixed&#x27;), undefined);</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.write(str)</h1>\n          <dl>\n            <dt>should write the given data</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.set(&#x27;Content-Type&#x27;, &#x27;application/json&#x27;);\nassert.equal(&#x27;boolean&#x27;, typeof request_.write(&#x27;{&#x22;name&#x22;&#x27;));\nassert.equal(&#x27;boolean&#x27;, typeof request_.write(&#x27;:&#x22;tobi&#x22;}&#x27;));\nrequest_.end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.pipe(stream)</h1>\n          <dl>\n            <dt>should pipe the response to the given stream</dt>\n            <dd><pre><code>const stream = new EventEmitter();\nstream.buf = &#x27;&#x27;;\nstream.writable = true;\nstream.write = function (chunk) {\n  this.buf += chunk;\n};\nstream.end = function () {\n  this.buf.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  done();\n};\nrequest.post(&#x60;${base}/echo&#x60;).send(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;).pipe(stream);</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.buffer()</h1>\n          <dl>\n            <dt>should enable buffering</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/custom&#x60;)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(&#x27;custom stuff&#x27;, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n            <dt>should take precedence over request.buffer[&#x27;someMimeType&#x27;] = false</dt>\n            <dd><pre><code>const type = &#x27;application/barbaz&#x27;;\nconst send = &#x27;some text&#x27;;\nrequest.buffer[type] = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .buffer()\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.buffer(false)</h1>\n          <dl>\n            <dt>should disable buffering</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-dog&#x27;)\n  .send(&#x27;hello this is dog&#x27;)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(&#x27;hello this is dog&#x27;);\n      done();\n    });\n  });</code></pre></dd>\n            <dt>should take precedence over request.buffer[&#x27;someMimeType&#x27;] = true</dt>\n            <dd><pre><code>const type = &#x27;application/foobar&#x27;;\nconst send = &#x27;hello this is a dog&#x27;;\nrequest.buffer[type] = true;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.withCredentials()</h1>\n          <dl>\n            <dt>should not throw an error when using the client-side &#x22;withCredentials&#x22; method</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/custom&#x60;)\n  .withCredentials()\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent()</h1>\n          <dl>\n            <dt>should return the defaut agent</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.agent().should.equal(false);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent(undefined)</h1>\n          <dl>\n            <dt>should set an agent to undefined and ensure it is chainable</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/echo&#x60;);\nconst returnValue = request_.agent(undefined);\nreturnValue.should.equal(request_);\nassert.strictEqual(request_.agent(), undefined);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>.agent(new http.Agent())</h1>\n          <dl>\n            <dt>should set passed agent</dt>\n            <dd><pre><code>const http = require(&#x27;http&#x27;);\nconst request_ = request.get(&#x60;${base}/echo&#x60;);\nconst agent = new http.Agent();\nconst returnValue = request_.agent(agent);\nreturnValue.should.equal(request_);\nrequest_.agent().should.equal(agent);\ndone();</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with a content type other than application/json or text/*</h1>\n          <dl>\n            <dt>should still use buffering</dt>\n            <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-dog&#x27;)\n  .send(&#x27;hello this is dog&#x27;)\n  .then((res) =&#x3E; {\n    assert.equal(null, res.text);\n    assert.equal(res.body.toString(), &#x27;hello this is dog&#x27;);\n    res.buffered.should.be.true;\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>content-length</h1>\n          <dl>\n            <dt>should be set to the byte length of a non-buffer object</dt>\n            <dd><pre><code>const decoder = new StringDecoder(&#x27;utf8&#x27;);\nlet img = fs.readFileSync(&#x60;${__dirname}/fixtures/test.png&#x60;);\nimg = decoder.write(img);\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-image&#x27;)\n  .send(img)\n  .buffer(false)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(!res.buffered);\n    assert.equal(res.header[&#x27;content-length&#x27;], Buffer.byteLength(img));\n    done();\n  });</code></pre></dd>\n            <dt>should be set to the length of a buffer object</dt>\n            <dd><pre><code>const img = fs.readFileSync(&#x60;${__dirname}/fixtures/test.png&#x60;);\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(&#x27;application/x-image&#x27;)\n  .send(img)\n  .buffer(true)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.buffered);\n    assert.equal(res.header[&#x27;content-length&#x27;], img.length);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.buffer[&#x27;someMimeType&#x27;]</h1>\n      <dl>\n        <dt>should respect that agent.buffer(true) takes precedent</dt>\n        <dd><pre><code>const agent = request.agent();\nagent.buffer(true);\nconst type = &#x27;application/somerandomtype&#x27;;\nconst send = &#x27;somerandomtext&#x27;;\nrequest.buffer[type] = false;\nagent\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n        <dt>should respect that agent.buffer(false) takes precedent</dt>\n        <dd><pre><code>const agent = request.agent();\nagent.buffer(false);\nconst type = &#x27;application/barrr&#x27;;\nconst send = &#x27;some random text2&#x27;;\nrequest.buffer[type] = true;\nagent\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n        <dt>should disable buffering for that mimetype when false</dt>\n        <dd><pre><code>const type = &#x27;application/bar&#x27;;\nconst send = &#x27;some random text&#x27;;\nrequest.buffer[type] = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(null, res.text);\n    assert.equal(res.type, type);\n    assert(!res.buffered);\n    res.body.should.eql({});\n    let buf = &#x27;&#x27;;\n    res.setEncoding(&#x27;utf8&#x27;);\n    res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n      buf += chunk;\n    });\n    res.on(&#x27;end&#x27;, () =&#x3E; {\n      buf.should.equal(send);\n      done();\n    });\n  });</code></pre></dd>\n        <dt>should enable buffering for that mimetype when true</dt>\n        <dd><pre><code>const type = &#x27;application/baz&#x27;;\nconst send = &#x27;woooo&#x27;;\nrequest.buffer[type] = true;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .end((error, res) =&#x3E; {\n    delete request.buffer[type];\n    assert.ifError(error);\n    assert.equal(res.type, type);\n    assert.equal(send, res.text);\n    assert(res.buffered);\n    done();\n  });</code></pre></dd>\n        <dt>should fallback to default handling for that mimetype when undefined</dt>\n        <dd><pre><code>const type = &#x27;application/bazzz&#x27;;\nconst send = &#x27;woooooo&#x27;;\nreturn request\n  .post(&#x60;${base}/echo&#x60;)\n  .type(type)\n  .send(send)\n  .then((res) =&#x3E; {\n    assert.equal(res.type, type);\n    assert.equal(send, res.body.toString());\n    assert(res.buffered);\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>exports</h1>\n      <dl>\n        <dt>should expose .protocols</dt>\n        <dd><pre><code>Object.keys(request.protocols).should.eql([&#x27;http:&#x27;, &#x27;https:&#x27;, &#x27;http2:&#x27;]);</code></pre></dd>\n        <dt>should expose .serialize</dt>\n        <dd><pre><code>Object.keys(request.serialize).should.eql([\n  &#x27;application/x-www-form-urlencoded&#x27;,\n  &#x27;application/json&#x27;\n]);</code></pre></dd>\n        <dt>should expose .parse</dt>\n        <dd><pre><code>Object.keys(request.parse).should.eql([\n  &#x27;application/x-www-form-urlencoded&#x27;,\n  &#x27;application/json&#x27;,\n  &#x27;text&#x27;,\n  &#x27;application/json-seq&#x27;,\n  &#x27;application/octet-stream&#x27;,\n  &#x27;application/pdf&#x27;,\n  &#x27;image&#x27;\n]);</code></pre></dd>\n        <dt>should export .buffer</dt>\n        <dd><pre><code>Object.keys(request.buffer).should.eql([]);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>flags</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>with 4xx response</h1>\n          <dl>\n            <dt>should set res.error and res.clientError</dt>\n            <dd><pre><code>request.get(&#x60;${base}/notfound&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(!res.ok, &#x27;response should not be ok&#x27;);\n  assert(res.error, &#x27;response should be an error&#x27;);\n  assert(res.clientError, &#x27;response should be a client error&#x27;);\n  assert(!res.serverError, &#x27;response should not be a server error&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 5xx response</h1>\n          <dl>\n            <dt>should set res.error and res.serverError</dt>\n            <dd><pre><code>request.get(&#x60;${base}/error&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(!res.ok, &#x27;response should not be ok&#x27;);\n  assert(!res.notFound, &#x27;response should not be notFound&#x27;);\n  assert(res.error, &#x27;response should be an error&#x27;);\n  assert(!res.clientError, &#x27;response should not be a client error&#x27;);\n  assert(res.serverError, &#x27;response should be a server error&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 404 Not Found</h1>\n          <dl>\n            <dt>should res.notFound</dt>\n            <dd><pre><code>request.get(&#x60;${base}/notfound&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.notFound, &#x27;response should be .notFound&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 400 Bad Request</h1>\n          <dl>\n            <dt>should set req.badRequest</dt>\n            <dd><pre><code>request.get(&#x60;${base}/bad-request&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.badRequest, &#x27;response should be .badRequest&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 401 Bad Request</h1>\n          <dl>\n            <dt>should set res.unauthorized</dt>\n            <dd><pre><code>request.get(&#x60;${base}/unauthorized&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.unauthorized, &#x27;response should be .unauthorized&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 406 Not Acceptable</h1>\n          <dl>\n            <dt>should set res.notAcceptable</dt>\n            <dd><pre><code>request.get(&#x60;${base}/not-acceptable&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(res.notAcceptable, &#x27;response should be .notAcceptable&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 204 No Content</h1>\n          <dl>\n            <dt>should set res.noContent</dt>\n            <dd><pre><code>request.get(&#x60;${base}/no-content&#x60;).end((error, res) =&#x3E; {\n  assert(!error);\n  assert(res.noContent, &#x27;response should be .noContent&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 201 Created</h1>\n          <dl>\n            <dt>should set res.created</dt>\n            <dd><pre><code>request.post(&#x60;${base}/created&#x60;).end((error, res) =&#x3E; {\n  assert(!error);\n  assert(res.created, &#x27;response should be .created&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>with 422 Unprocessable Entity</h1>\n          <dl>\n            <dt>should set res.unprocessableEntity</dt>\n            <dd><pre><code>request.post(&#x60;${base}/unprocessable-entity&#x60;).end((error, res) =&#x3E; {\n  assert(error);\n  assert(\n    res.unprocessableEntity,\n    &#x27;response should be .unprocessableEntity&#x27;\n  );\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Merging objects</h1>\n      <dl>\n        <dt>Don&#x27;t mix Buffer and JSON</dt>\n        <dd><pre><code>assert.throws(() =&#x3E; {\n  request\n    .post(&#x27;/echo&#x27;)\n    .send(Buffer.from(&#x27;some buffer&#x27;))\n    .send({ allowed: false });\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.send(String)</h1>\n      <dl>\n        <dt>should default to &#x22;form&#x22;</dt>\n        <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .send(&#x27;user[name]=tj&#x27;)\n  .send(&#x27;user[email]=tj@vision-media.ca&#x27;)\n  .end((error, res) =&#x3E; {\n    res.header[&#x27;content-type&#x27;].should.equal(\n      &#x27;application/x-www-form-urlencoded&#x27;\n    );\n    res.body.should.eql({\n      user: { name: &#x27;tj&#x27;, email: &#x27;tj@vision-media.ca&#x27; }\n    });\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>application/x-www-form-urlencoded</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${base}/form-data&#x60;).end((error, res) =&#x3E; {\n  res.text.should.equal(&#x27;pet[name]=manny&#x27;);\n  res.body.should.eql({ pet: { name: &#x27;manny&#x27; } });\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.get().http2()</h1>\n      <dl>\n        <dt>should preserve the encoding of the url</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/url?a=(b%29&#x60;)\n  .http2()\n  .end((error, res) =&#x3E; {\n    assert.equal(&#x27;/url?a=(b%29&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n        <dt>should format the url</dt>\n        <dd><pre><code>request\n      .get(url.parse(&#x60;${base}/login&#x60;))\n      .http2()\n      .then((res) =&#x3E; {\n        assert(res.ok);\n      })</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>https</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>certificate authority</h1>\n          <dl>\n            <section class=\"suite\">\n              <h1>request</h1>\n              <dl>\n                <dt>should give a good response</dt>\n                <dd><pre><code>request\n  .get(testEndpoint)\n  .ca(ca)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n                <dt>should reject unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(testEndpoint)\n  .trustLocalhost(false)\n  .then(\n    () =&#x3E; {\n      throw new Error(&#x27;Allows MITM&#x27;);\n    },\n    () =&#x3E; {}\n  );</code></pre></dd>\n                <dt>should not reject unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(testEndpoint)\n  .disableTLSCerts()\n  .then(({ status }) =&#x3E; {\n    assert.strictEqual(status, 200);\n  });</code></pre></dd>\n                <dt>should trust localhost unauthorized response</dt>\n                <dd><pre><code>return request.get(testEndpoint).trustLocalhost(true);</code></pre></dd>\n                <dt>should trust overriden localhost unauthorized response</dt>\n                <dd><pre><code>return request\n  .get(&#x60;https://example.com:${server.address().port}&#x60;)\n  .connect(&#x27;127.0.0.1&#x27;)\n  .trustLocalhost();</code></pre></dd>\n              </dl>\n            </section>\n            <section class=\"suite\">\n              <h1>.agent</h1>\n              <dl>\n                <dt>should be able to make multiple requests without redefining the certificate</dt>\n                <dd><pre><code>const agent = request.agent({ ca });\nagent.get(testEndpoint).end((error, res) =&#x3E; {\n  assert.ifError(error);\n  assert(res.ok);\n  assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n  agent.get(url.parse(testEndpoint)).end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;Safe and secure!&#x27;, res.text);\n    done();\n  });\n});</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>client certificates</h1>\n          <dl>\n            <section class=\"suite\">\n              <h1>request</h1>\n              <dl>\n              </dl>\n            </section>\n            <section class=\"suite\">\n              <h1>.agent</h1>\n              <dl>\n              </dl>\n            </section>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.body</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>image/png</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request.get(&#x60;${base}/image&#x60;).end((error, res) =&#x3E; {\n  res.type.should.equal(&#x27;image/png&#x27;);\n  Buffer.isBuffer(res.body).should.be.true();\n  (res.body.length - img.length).should.equal(0);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>application/octet-stream</h1>\n          <dl>\n            <dt>should parse the body</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/image-as-octets&#x60;)\n  .buffer(true) // that&#x27;s tech debt :(\n  .end((error, res) =&#x3E; {\n    res.type.should.equal(&#x27;application/octet-stream&#x27;);\n    Buffer.isBuffer(res.body).should.be.true();\n    (res.body.length - img.length).should.equal(0);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>application/octet-stream</h1>\n          <dl>\n            <dt>should parse the body (using responseType)</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/image-as-octets&#x60;)\n  .responseType(&#x27;blob&#x27;)\n  .end((error, res) =&#x3E; {\n    res.type.should.equal(&#x27;application/octet-stream&#x27;);\n    Buffer.isBuffer(res.body).should.be.true();\n    (res.body.length - img.length).should.equal(0);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>zlib</h1>\n      <dl>\n        <dt>should deflate the content</dt>\n        <dd><pre><code>request.get(base).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.equal(subject);\n  res.headers[&#x27;content-length&#x27;].should.be.below(subject.length);\n  done();\n});</code></pre></dd>\n        <dt>should protect from zip bombs</dt>\n        <dd><pre><code>request\n  .get(base)\n  .buffer(true)\n  .maxResponseSize(1)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.equal(&#x27;Maximum response size reached&#x27;, error &#x26;&#x26; error.message);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n        <dt>should ignore trailing junk</dt>\n        <dd><pre><code>request.get(&#x60;${base}/junk&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.equal(subject);\n  done();\n});</code></pre></dd>\n        <dt>should ignore missing data</dt>\n        <dd><pre><code>request.get(&#x60;${base}/chopped&#x60;).end((error, res) =&#x3E; {\n  assert.equal(undefined, error);\n  res.should.have.status(200);\n  res.text.should.startWith(subject);\n  done();\n});</code></pre></dd>\n        <dt>should handle corrupted responses</dt>\n        <dd><pre><code>request.get(&#x60;${base}/corrupt&#x60;).end((error, res) =&#x3E; {\n  assert(error, &#x27;missing error&#x27;);\n  assert(!res, &#x27;response should not be defined&#x27;);\n  done();\n});</code></pre></dd>\n        <dt>should handle no content with gzip header</dt>\n        <dd><pre><code>request.get(&#x60;${base}/nocontent&#x60;).end((error, res) =&#x3E; {\n  assert.ifError(error);\n  assert(res);\n  res.should.have.status(204);\n  res.text.should.equal(&#x27;&#x27;);\n  res.headers.should.not.have.property(&#x27;content-length&#x27;);\n  done();\n});</code></pre></dd>\n        <section class=\"suite\">\n          <h1>without encoding set</h1>\n          <dl>\n            <dt>should buffer if asked</dt>\n            <dd><pre><code>return request\n  .get(&#x60;${base}/binary&#x60;)\n  .buffer(true)\n  .then((res) =&#x3E; {\n    res.should.have.status(200);\n    assert(res.headers[&#x27;content-length&#x27;]);\n    assert(res.body.byteLength);\n    assert.equal(subject, res.body.toString());\n  });</code></pre></dd>\n            <dt>should emit buffers</dt>\n            <dd><pre><code>request.get(&#x60;${base}/binary&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.headers[&#x27;content-length&#x27;].should.be.below(subject.length);\n  res.on(&#x27;data&#x27;, (chunk) =&#x3E; {\n    chunk.should.have.length(subject.length);\n  });\n  res.on(&#x27;end&#x27;, done);\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.lookup()</h1>\n      <dl>\n        <dt>should set a custom lookup</dt>\n        <dd><pre><code>const r = request.get(&#x60;${base}/ok&#x60;).lookup(myLookup);\nassert(r.lookup() === myLookup);\nr.then((res) =&#x3E; {\n  res.text.should.equal(&#x27;ok&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>Multipart</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>#field(name, value)</h1>\n          <dl>\n            <dt>should set a multipart field value</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.field(&#x27;user[name]&#x27;, &#x27;tobi&#x27;);\nrequest_.field(&#x27;user[age]&#x27;, &#x27;2&#x27;);\nrequest_.field(&#x27;user[species]&#x27;, &#x27;ferret&#x27;);\nreturn request_.then((res) =&#x3E; {\n  res.body[&#x27;user[name]&#x27;].should.equal(&#x27;tobi&#x27;);\n  res.body[&#x27;user[age]&#x27;].should.equal(&#x27;2&#x27;);\n  res.body[&#x27;user[species]&#x27;].should.equal(&#x27;ferret&#x27;);\n});</code></pre></dd>\n            <dt>should work with file attachments</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.field(&#x27;name&#x27;, &#x27;Tobi&#x27;);\nrequest_.attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;);\nrequest_.field(&#x27;species&#x27;, &#x27;ferret&#x27;);\nreturn request_.then((res) =&#x3E; {\n  res.body.name.should.equal(&#x27;Tobi&#x27;);\n  res.body.species.should.equal(&#x27;ferret&#x27;);\n  const html = res.files.document;\n  html.originalFilename.should.equal(&#x27;user.html&#x27;);\n  html.mimetype.should.equal(&#x27;text/html&#x27;);\n  read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#attach(name, path)</h1>\n          <dl>\n            <dt>should attach a file</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.attach(&#x27;one&#x27;, &#x27;test/node/fixtures/user.html&#x27;);\nrequest_.attach(&#x27;two&#x27;, &#x27;test/node/fixtures/user.json&#x27;);\nrequest_.attach(&#x27;three&#x27;, &#x27;test/node/fixtures/user.txt&#x27;);\nreturn request_.then((res) =&#x3E; {\n  const html = res.files.one;\n  const json = res.files.two;\n  const text = res.files.three;\n  html.originalFilename.should.equal(&#x27;user.html&#x27;);\n  html.mimetype.should.equal(&#x27;text/html&#x27;);\n  read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n  json.originalFilename.should.equal(&#x27;user.json&#x27;);\n  json.mimetype.should.equal(&#x27;application/json&#x27;);\n  read(json.filepath).should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);\n  text.originalFilename.should.equal(&#x27;user.txt&#x27;);\n  text.mimetype.should.equal(&#x27;text/plain&#x27;);\n  read(text.filepath).should.equal(&#x27;Tobi&#x27;);\n});</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when a file does not exist</h1>\n              <dl>\n                <dt>should fail the request with an error</dt>\n                <dd><pre><code>const request_ = request.post(&#x60;${base}/echo&#x60;);\nrequest_.attach(&#x27;name&#x27;, &#x27;foo&#x27;);\n// request_.attach(&#x27;name2&#x27;, &#x27;bar&#x27;);\n// request_.attach(&#x27;name3&#x27;, &#x27;baz&#x27;);\nrequest_.end((error, res) =&#x3E; {\n  assert.ok(Boolean(error), &#x27;Request should have failed.&#x27;);\n  error.code.should.equal(&#x27;ENOENT&#x27;);\n  error.message.should.containEql(&#x27;ENOENT&#x27;);\n  if (IS_WINDOWS) {\n    error.path.toLowerCase().should.equal(\n      getFullPath(&#x27;foo&#x27;).toLowerCase()\n    );\n  } else {\n    error.path.should.equal(getFullPath(&#x27;foo&#x27;));\n  }\n  done();\n});</code></pre></dd>\n                <dt>promise should fail</dt>\n                <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .field({ a: 1, b: 2 })\n  .attach(&#x27;c&#x27;, &#x27;does-not-exist.txt&#x27;)\n  .then(\n    (res) =&#x3E; assert.fail(&#x27;It should not allow this&#x27;),\n    (err) =&#x3E; {\n      err.code.should.equal(&#x27;ENOENT&#x27;);\n      if (IS_WINDOWS) {\n        err.path.toLowerCase().should.equal(\n          getFullPath(&#x27;does-not-exist.txt&#x27;).toLowerCase()\n        );\n      } else {\n        err.path.should.equal(getFullPath(&#x27;does-not-exist.txt&#x27;));\n      }\n    }\n  );</code></pre></dd>\n                <dt>should report ENOENT via the callback</dt>\n                <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;name&#x27;, &#x27;file-does-not-exist&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ok(Boolean(error), &#x27;Request should have failed&#x27;);\n    error.code.should.equal(&#x27;ENOENT&#x27;);\n    done();\n  });</code></pre></dd>\n                <dt>should report ENOENT via Promise</dt>\n                <dd><pre><code>return request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;name&#x27;, &#x27;file-does-not-exist&#x27;)\n  .then(\n    (res) =&#x3E; assert.fail(&#x27;Request should have failed&#x27;),\n    (err) =&#x3E; err.code.should.equal(&#x27;ENOENT&#x27;)\n  );</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#attach(name, path, filename)</h1>\n          <dl>\n            <dt>should use the custom filename</dt>\n            <dd><pre><code>request\n        .post(&#x60;${base}/echo&#x60;)\n        .attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;, &#x27;doc.html&#x27;)\n        .then((res) =&#x3E; {\n          const html = res.files.document;\n          html.originalFilename.should.equal(&#x27;doc.html&#x27;);\n          html.mimetype.should.equal(&#x27;text/html&#x27;);\n          read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n        })</code></pre></dd>\n            <dt>should fire progress event</dt>\n            <dd><pre><code>let loaded = 0;\nlet total = 0;\nlet uploadEventWasFired = false;\nrequest\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;document&#x27;, &#x27;test/node/fixtures/user.html&#x27;)\n  .on(&#x27;progress&#x27;, (event) =&#x3E; {\n    total = event.total;\n    loaded = event.loaded;\n    if (event.direction === &#x27;upload&#x27;) {\n      uploadEventWasFired = true;\n    }\n  })\n  .end((error, res) =&#x3E; {\n    if (error) return done(error);\n    const html = res.files.document;\n    html.originalFilename.should.equal(&#x27;user.html&#x27;);\n    html.mimetype.should.equal(&#x27;text/html&#x27;);\n    read(html.filepath).should.equal(&#x27;&#x3C;h1&#x3E;name&#x3C;/h1&#x3E;&#x27;);\n    total.should.equal(223);\n    loaded.should.equal(223);\n    uploadEventWasFired.should.equal(true);\n    done();\n  });</code></pre></dd>\n            <dt>filesystem errors should be caught</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .attach(&#x27;filedata&#x27;, &#x27;test/node/fixtures/non-existent-file.ext&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ok(Boolean(error), &#x27;Request should have failed.&#x27;);\n    error.code.should.equal(&#x27;ENOENT&#x27;);\n    if (IS_WINDOWS) {\n      error.path.toLowerCase().should.equal(\n        getFullPath(&#x27;test/node/fixtures/non-existent-file.ext&#x27;).toLowerCase()\n      );\n    } else {\n      error.path.should.equal(\n        getFullPath(&#x27;test/node/fixtures/non-existent-file.ext&#x27;)\n      );\n    }\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#field(name, val)</h1>\n          <dl>\n            <dt>should set a multipart field value</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .field(&#x27;first-name&#x27;, &#x27;foo&#x27;)\n  .field(&#x27;last-name&#x27;, &#x27;bar&#x27;)\n  .end((error, res) =&#x3E; {\n    if (error) done(error);\n    res.should.be.ok();\n    res.body[&#x27;first-name&#x27;].should.equal(&#x27;foo&#x27;);\n    res.body[&#x27;last-name&#x27;].should.equal(&#x27;bar&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>#field(object)</h1>\n          <dl>\n            <dt>should set multiple multipart fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .field({ &#x27;first-name&#x27;: &#x27;foo&#x27;, &#x27;last-name&#x27;: &#x27;bar&#x27; })\n  .end((error, res) =&#x3E; {\n    if (error) done(error);\n    res.should.be.ok();\n    res.body[&#x27;first-name&#x27;].should.equal(&#x27;foo&#x27;);\n    res.body[&#x27;last-name&#x27;].should.equal(&#x27;bar&#x27;);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>with network error</h1>\n      <dl>\n        <dt>should error</dt>\n        <dd><pre><code>request.get(&#x60;http://localhost:${this.port}/&#x60;).end((error, res) =&#x3E; {\n  assert(error, &#x27;expected an error&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>not modified</h1>\n          <dl>\n            <dt>should start with 200</dt>\n            <dd><pre><code>request.get(&#x60;${base}/if-mod&#x60;).end((error, res) =&#x3E; {\n  res.should.have.status(200);\n  res.text.should.match(/^\\d+$/);\n  ts = Number(res.text);\n  done();\n});</code></pre></dd>\n            <dt>should then be 304</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/if-mod&#x60;)\n  .set(&#x27;If-Modified-Since&#x27;, new Date(ts).toUTCString())\n  .end((error, res) =&#x3E; {\n    res.should.have.status(304);\n    // res.text.should.be.empty\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.parse(fn)</h1>\n      <dl>\n        <dt>should take precedence over default parsers</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse(request.parse[&#x27;application/json&#x27;])\n  .end((error, res) =&#x3E; {\n    assert(res.ok);\n    assert.equal(&#x27;{&#x22;name&#x22;:&#x22;manny&#x22;}&#x27;, res.text);\n    assert.equal(&#x27;manny&#x27;, res.body.name);\n    done();\n  });</code></pre></dd>\n        <dt>should be the only parser</dt>\n        <dd><pre><code>request\n      .get(&#x60;${base}/image&#x60;)\n      .buffer(false)\n      .parse((res, fn) =&#x3E; {\n        res.on(&#x27;data&#x27;, () =&#x3E; {});\n      })\n      .then((res) =&#x3E; {\n        assert(res.ok);\n        assert.strictEqual(res.text, undefined);\n        res.body.should.eql({});\n      })</code></pre></dd>\n        <dt>should emit error if parser throws</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse(() =&#x3E; {\n    throw new Error(&#x27;I am broken&#x27;);\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    error.message.should.equal(&#x27;I am broken&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n        <dt>should emit error if parser returns an error</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/manny&#x60;)\n  .parse((res, fn) =&#x3E; {\n    fn(new Error(&#x27;I am broken&#x27;));\n  })\n  .on(&#x27;error&#x27;, (error) =&#x3E; {\n    error.message.should.equal(&#x27;I am broken&#x27;);\n    done();\n  })\n  .end();</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>pipe on redirect</h1>\n      <dl>\n        <dt>should follow Location</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nconst redirects = [];\nconst request_ = request\n  .get(base)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .connect({\n    inapplicable: &#x27;should be ignored&#x27;\n  });\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  redirects.should.eql([&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;]);\n  fs.readFileSync(destinationPath, &#x27;utf8&#x27;).should.eql(&#x27;first movie page&#x27;);\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request pipe</h1>\n      <dl>\n        <dt>should act as a writable stream</dt>\n        <dd><pre><code>const request_ = request.post(base);\nconst stream = fs.createReadStream(&#x27;test/node/fixtures/user.json&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});\nstream.pipe(request_);</code></pre></dd>\n        <dt>end() stops piping</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nrequest.get(base).end((error, res) =&#x3E; {\n  try {\n    res.pipe(stream);\n    return done(new Error(&#x27;Did not prevent nonsense pipe&#x27;));\n  } catch {\n    /* expected error */\n  }\n  done();\n});</code></pre></dd>\n        <dt>should act as a readable stream</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nconst request_ = request.get(base);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.status.should.eql(200);\n  responseCalled = true;\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n    name: &#x27;tobi&#x27;\n  });\n  responseCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n        <dt>should follow redirects</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nconst request_ = request.get(base + &#x27;/redirect&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.status.should.eql(200);\n  responseCalled = true;\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n    name: &#x27;tobi&#x27;\n  });\n  responseCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n        <dt>should not throw on bad redirects</dt>\n        <dd><pre><code>const stream = fs.createWriteStream(destinationPath);\nlet responseCalled = false;\nlet errorCalled = false;\nconst request_ = request.get(base + &#x27;/badRedirectNoLocation&#x27;);\nrequest_.type(&#x27;json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  responseCalled = true;\n});\nrequest_.on(&#x27;error&#x27;, (error) =&#x3E; {\n  error.message.should.eql(&#x27;No location header for redirect&#x27;);\n  errorCalled = true;\n  stream.end();\n});\nstream.on(&#x27;finish&#x27;, () =&#x3E; {\n  responseCalled.should.be.false();\n  errorCalled.should.be.true();\n  done();\n});\nrequest_.pipe(stream);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.query(String)</h1>\n      <dl>\n        <dt>should support passing in a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work with url query-string and string for query</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/?name=tobi&#x60;)\n  .query(&#x27;age=2%20&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, age: &#x27;2 &#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should support compound elements in a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x26;age=2&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work when called multiple times with a string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .query(&#x27;age=2%F6&#x27;)\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2%F6&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should work with normal &#x60;query&#x60; object and query string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query(&#x27;name=t%F6bi&#x27;)\n  .query({ age: &#x27;2&#x27; })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;t%F6bi&#x27;, age: &#x27;2&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should not encode raw backticks, but leave encoded ones as is</dt>\n        <dd><pre><code>return Promise.all([\n  request\n    .get(&#x60;${base}/raw-query&#x60;)\n    .query(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;)\n    .then((res) =&#x3E; {\n      res.text.should.eql(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;);\n    }),\n  request.get(base + &#x27;/raw-query?&#x60;age%60&#x60;=2%60&#x60;&#x27;).then((res) =&#x3E; {\n    res.text.should.eql(&#x27;&#x60;age%60&#x60;=2%60&#x60;&#x27;);\n  }),\n  request\n    .get(&#x60;${base}/raw-query&#x60;)\n    .query(&#x27;name=&#x60;t%60bi&#x60;&#x27;)\n    .query(&#x27;age&#x60;=2&#x27;)\n    .then((res) =&#x3E; {\n      res.text.should.eql(&#x27;name=&#x60;t%60bi&#x60;&#x26;age&#x60;=2&#x27;);\n    })\n]);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.query(Object)</h1>\n      <dl>\n        <dt>should construct the query-string</dt>\n        <dd><pre><code>request\n  .del(base)\n  .query({ name: &#x27;tobi&#x27; })\n  .query({ order: &#x27;asc&#x27; })\n  .query({ limit: [&#x27;1&#x27;, &#x27;2&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27;, limit: [&#x27;1&#x27;, &#x27;2&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>should encode raw backticks</dt>\n        <dd><pre><code>request\n  .get(&#x60;${base}/raw-query&#x60;)\n  .query({ name: &#x27;&#x60;tobi&#x60;&#x27; })\n  .query({ &#x27;orde%60r&#x27;: null })\n  .query({ &#x27;&#x60;limit&#x60;&#x27;: [&#x27;%602&#x60;&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.text.should.eql(&#x27;name=%60tobi%60&#x26;orde%2560r&#x26;%60limit%60=%25602%60&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>should not error on dates</dt>\n        <dd><pre><code>const date = new Date(0);\nrequest\n  .del(base)\n  .query({ at: date })\n  .end((error, res) =&#x3E; {\n    assert.equal(date.toISOString(), res.body.at);\n    done();\n  });</code></pre></dd>\n        <dt>should work after setting header fields</dt>\n        <dd><pre><code>request\n  .del(base)\n  .set(&#x27;Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;Bar&#x27;, &#x27;baz&#x27;)\n  .query({ name: &#x27;tobi&#x27; })\n  .query({ order: &#x27;asc&#x27; })\n  .query({ limit: [&#x27;1&#x27;, &#x27;2&#x27;] })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27;, limit: [&#x27;1&#x27;, &#x27;2&#x27;] });\n    done();\n  });</code></pre></dd>\n        <dt>should append to the original query-string</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/?name=tobi&#x60;)\n  .query({ order: &#x27;asc&#x27; })\n  .end((error, res) =&#x3E; {\n    res.body.should.eql({ name: &#x27;tobi&#x27;, order: &#x27;asc&#x27; });\n    done();\n  });</code></pre></dd>\n        <dt>should retain the original query-string</dt>\n        <dd><pre><code>request.del(&#x60;${base}/?name=tobi&#x60;).end((error, res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});</code></pre></dd>\n        <dt>should keep only keys with null querystring values</dt>\n        <dd><pre><code>request\n  .del(&#x60;${base}/url&#x60;)\n  .query({ nil: null })\n  .end((error, res) =&#x3E; {\n    res.text.should.equal(&#x27;/url?nil&#x27;);\n    done();\n  });</code></pre></dd>\n        <dt>query-string should be sent on pipe</dt>\n        <dd><pre><code>this.timeout(15_000);\nconst request_ = request.put(&#x60;${base}/?name=tobi&#x60;);\nconst stream = fs.createReadStream(&#x27;test/node/fixtures/user.json&#x27;);\nrequest_.on(&#x27;response&#x27;, (res) =&#x3E; {\n  res.body.should.eql({ name: &#x27;tobi&#x27; });\n  done();\n});\nrequest_.on(&#x27;error&#x27;, (err) =&#x3E; {\n  done(err);\n});\nstream.on(&#x27;error&#x27;, function (err) {\n  done(err);\n});\nstream.pipe(request_);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.get</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on 301 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-301&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 302 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-302&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-303&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-307&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.get(&#x60;${base}/test-308&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request.post</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on 301 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-301&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 302 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-302&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 303 redirect</h1>\n          <dl>\n            <dt>should follow Location with a GET request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-303&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;GET&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 307 redirect</h1>\n          <dl>\n            <dt>should follow Location with a POST request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-307&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;POST&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on 308 redirect</h1>\n          <dl>\n            <dt>should follow Location with a POST request</dt>\n            <dd><pre><code>const request_ = request.post(&#x60;${base}/test-308&#x60;).redirects(1);\nrequest_.end((error, res) =&#x3E; {\n  const headers = request_.req.getHeaders\n    ? request_.req.getHeaders()\n    : request_.req._headers;\n  headers.host.should.eql(&#x60;localhost:${server2.address().port}&#x60;);\n  res.status.should.eql(200);\n  res.text.should.eql(&#x27;POST&#x27;);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>request</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>on redirect</h1>\n          <dl>\n            <dt>should merge cookies if agent is used</dt>\n            <dd><pre><code>request\n  .agent()\n  .get(&#x60;${base}/cookie-redirect&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;orig=1; replaced=not&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(/orig=1/.test(res.text), &#x27;orig=1/.test&#x27;);\n      assert(/replaced=yes/.test(res.text), &#x27;replaced=yes/.test&#x27;);\n      assert(/from-redir=1/.test(res.text), &#x27;from-redir=1&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should not merge cookies if agent is not used</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/cookie-redirect&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;orig=1; replaced=not&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert.ifError(error);\n      assert(/orig=1/.test(res.text), &#x27;/orig=1&#x27;);\n      assert(/replaced=not/.test(res.text), &#x27;/replaced=not&#x27;);\n      assert(!/replaced=yes/.test(res.text), &#x27;!/replaced=yes&#x27;);\n      assert(!/from-redir/.test(res.text), &#x27;!/from-redir&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should have previously set cookie for subsquent requests when agent is used</dt>\n            <dd><pre><code>const agent = request.agent();\nagent.get(&#x60;${base}/set-cookie&#x60;).end((error) =&#x3E; {\n  assert.ifError(error);\n  agent\n    .get(&#x60;${base}/show-cookies&#x60;)\n    .set({ Cookie: &#x27;orig=1&#x27; })\n    .end((error, res) =&#x3E; {\n      try {\n        assert.ifError(error);\n        assert(/orig=1/.test(res.text), &#x27;orig=1/.test&#x27;);\n        assert(/persist=123/.test(res.text), &#x27;persist=123&#x27;);\n        done();\n      } catch (err) {\n        done(err);\n      }\n    });\n});</code></pre></dd>\n            <dt>should follow Location</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .get(base)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n      redirects.should.eql(array);\n      res.text.should.equal(&#x27;first movie page&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should follow Location with IP override</dt>\n            <dd><pre><code>const redirects = [];\nconst url = URL.parse(base);\nreturn request\n  .get(&#x60;http://redir.example.com:${url.port || &#x27;80&#x27;}${url.pathname}&#x60;)\n  .connect({\n    &#x27;*&#x27;: url.hostname\n  })\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n    redirects.should.eql(array);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>should follow Location with IP:port override</dt>\n            <dd><pre><code>const redirects = [];\nconst url = URL.parse(base);\nreturn request\n  .get(&#x60;http://redir.example.com:9999${url.pathname}&#x60;)\n  .connect({\n    &#x27;*&#x27;: { host: url.hostname, port: url.port || 80 }\n  })\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    const array = [&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;];\n    redirects.should.eql(array);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>should not follow on HEAD by default</dt>\n            <dd><pre><code>const redirects = [];\nreturn request\n  .head(base)\n  .ok(() =&#x3E; true)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([]);\n    res.status.should.equal(302);\n  });</code></pre></dd>\n            <dt>should follow on HEAD when redirects are set</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .head(base)\n  .redirects(10)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;);\n      redirects.should.eql(array);\n      assert(!res.text);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should remove Content-* fields</dt>\n            <dd><pre><code>request\n  .post(&#x60;${base}/header&#x60;)\n  .type(&#x27;txt&#x27;)\n  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)\n  .set(&#x27;X-Bar&#x27;, &#x27;baz&#x27;)\n  .send(&#x27;hey&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);\n      res.body.should.have.property(&#x27;x-bar&#x27;, &#x27;baz&#x27;);\n      res.body.should.not.have.property(&#x27;content-type&#x27;);\n      res.body.should.not.have.property(&#x27;content-length&#x27;);\n      res.body.should.not.have.property(&#x27;transfer-encoding&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should retain cookies</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/header&#x60;)\n  .set(&#x27;Cookie&#x27;, &#x27;foo=bar;&#x27;)\n  .end((error, res) =&#x3E; {\n    try {\n      assert(res.body);\n      res.body.should.have.property(&#x27;cookie&#x27;, &#x27;foo=bar;&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should not resend query parameters</dt>\n            <dd><pre><code>const redirects = [];\nconst query = [];\nrequest\n  .get(&#x60;${base}/?foo=bar&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    query.push(res.headers.query);\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;, &#x27;/movies/all/0&#x27;);\n      redirects.should.eql(array);\n      res.text.should.equal(&#x27;first movie page&#x27;);\n      query.should.eql([&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, &#x27;{}&#x27;, &#x27;{}&#x27;]);\n      res.headers.query.should.eql(&#x27;{}&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n            <dt>should handle no location header</dt>\n            <dd><pre><code>request.get(&#x60;${base}/bad-redirect&#x60;).end((error, res) =&#x3E; {\n  try {\n    error.message.should.equal(&#x27;No location header for redirect&#x27;);\n    done();\n  } catch (err) {\n    done(err);\n  }\n});</code></pre></dd>\n            <section class=\"suite\">\n              <h1>when relative</h1>\n              <dl>\n                <dt>should redirect to a sibling path</dt>\n                <dd><pre><code>const redirects = [];\nrequest\n  .get(&#x60;${base}/relative&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      redirects.should.eql([&#x27;tobi&#x27;]);\n      res.text.should.equal(&#x27;tobi&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n                <dt>should redirect to a parent path</dt>\n                <dd><pre><code>const redirects = [];\nrequest\n  .get(&#x60;${base}/relative/sub&#x60;)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      redirects.should.eql([&#x27;../tobi&#x27;]);\n      res.text.should.equal(&#x27;tobi&#x27;);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n              </dl>\n            </section>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>req.redirects(n)</h1>\n          <dl>\n            <dt>should alter the default number of redirects to follow</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .get(base)\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .end((error, res) =&#x3E; {\n    try {\n      const array = [];\n      assert(res.redirect, &#x27;res.redirect&#x27;);\n      array.push(&#x27;/movies&#x27;, &#x27;/movies/all&#x27;);\n      redirects.should.eql(array);\n      res.text.should.match(/Moved Temporarily|Found/);\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });</code></pre></dd>\n          </dl>\n        </section>\n        <section class=\"suite\">\n          <h1>on POST</h1>\n          <dl>\n            <dt>should redirect as GET</dt>\n            <dd><pre><code>const redirects = [];\nreturn request\n  .post(&#x60;${base}/movie&#x60;)\n  .send({ name: &#x27;Tobi&#x27; })\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([&#x27;/movies/all/0&#x27;]);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n            <dt>using multipart/form-data should redirect as GET</dt>\n            <dd><pre><code>const redirects = [];\nrequest\n  .post(&#x60;${base}/movie&#x60;)\n  .type(&#x27;form&#x27;)\n  .field(&#x27;name&#x27;, &#x27;Tobi&#x27;)\n  .redirects(2)\n  .on(&#x27;redirect&#x27;, (res) =&#x3E; {\n    redirects.push(res.headers.location);\n  })\n  .then((res) =&#x3E; {\n    redirects.should.eql([&#x27;/movies/all/0&#x27;]);\n    res.text.should.equal(&#x27;first movie page&#x27;);\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>response</h1>\n      <dl>\n        <dt>should act as a readable stream</dt>\n        <dd><pre><code>const request_ = request.get(base).buffer(false);\nrequest_.end((error, res) =&#x3E; {\n  if (error) return done(error);\n  let trackEndEvent = 0;\n  let trackCloseEvent = 0;\n  res.on(&#x27;end&#x27;, () =&#x3E; {\n    trackEndEvent++;\n    trackEndEvent.should.equal(1);\n    if (!process.env.HTTP2_TEST) {\n      trackCloseEvent.should.equal(0); // close should not have been called\n    }\n    done();\n  });\n  res.on(&#x27;close&#x27;, () =&#x3E; {\n    trackCloseEvent++;\n  });\n  setTimeout(() =&#x3E; {\n    (() =&#x3E; {\n      res.pause();\n    }).should.not.throw();\n    (() =&#x3E; {\n      res.resume();\n    }).should.not.throw();\n    (() =&#x3E; {\n      res.destroy();\n    }).should.not.throw();\n  }, 50);\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.serialize(fn)</h1>\n      <dl>\n        <dt>should take precedence over default parsers</dt>\n        <dd><pre><code>request\n  .post(&#x60;${base}/echo&#x60;)\n  .send({ foo: 123 })\n  .serialize(() =&#x3E; &#x27;{&#x22;bar&#x22;:456}&#x27;)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert.equal(&#x27;{&#x22;bar&#x22;:456}&#x27;, res.text);\n    assert.equal(456, res.body.bar);\n    done();\n  });</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>res.toError()</h1>\n      <dl>\n        <dt>should return an Error</dt>\n        <dd><pre><code>request.get(base).end((err, res) =&#x3E; {\n  const error = res.toError();\n  assert.equal(error.status, 400);\n  assert.equal(error.method, &#x27;GET&#x27;);\n  assert.equal(error.path, &#x27;/&#x27;);\n  assert.equal(error.message, &#x27;cannot GET / (400)&#x27;);\n  assert.equal(error.text, &#x27;invalid json&#x27;);\n  done();\n});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[unix-sockets] http</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>request</h1>\n          <dl>\n            <dt>path: / (root)</dt>\n            <dd><pre><code>request.get(&#x60;${base}/&#x60;).end((error, res) =&#x3E; {\n  assert(res.ok);\n  assert.strictEqual(&#x27;root ok!&#x27;, res.text);\n  done();\n});</code></pre></dd>\n            <dt>path: /request/path</dt>\n            <dd><pre><code>request.get(&#x60;${base}/request/path&#x60;).end((error, res) =&#x3E; {\n  assert(res.ok);\n  assert.strictEqual(&#x27;request path ok!&#x27;, res.text);\n  done();\n});</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>[unix-sockets] https</h1>\n      <dl>\n        <section class=\"suite\">\n          <h1>request</h1>\n          <dl>\n            <dt>path: / (root)</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/&#x60;)\n  .ca(cacert)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;root ok!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n            <dt>path: /request/path</dt>\n            <dd><pre><code>request\n  .get(&#x60;${base}/request/path&#x60;)\n  .ca(cacert)\n  .end((error, res) =&#x3E; {\n    assert.ifError(error);\n    assert(res.ok);\n    assert.strictEqual(&#x27;request path ok!&#x27;, res.text);\n    done();\n  });</code></pre></dd>\n          </dl>\n        </section>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>req.get()</h1>\n      <dl>\n        <dt>should not set a default user-agent</dt>\n        <dd><pre><code>request.get(&#x60;${base}/ua&#x60;).then((res) =&#x3E; {\n      assert(res.headers);\n      assert(!res.headers[&#x27;user-agent&#x27;]);\n    })</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.type(str)</h1>\n      <dl>\n        <dt>should return the mime type</dt>\n        <dd><pre><code>utils\n  .type(&#x27;application/json; charset=utf-8&#x27;)\n  .should.equal(&#x27;application/json&#x27;);\nutils.type(&#x27;application/json&#x27;).should.equal(&#x27;application/json&#x27;);</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.params(str)</h1>\n      <dl>\n        <dt>should return the field parameters</dt>\n        <dd><pre><code>const object = utils.params(&#x27;application/json; charset=utf-8; foo  = bar&#x27;);\nobject.charset.should.equal(&#x27;utf-8&#x27;);\nobject.foo.should.equal(&#x27;bar&#x27;);\nutils.params(&#x27;application/json&#x27;).should.eql({});</code></pre></dd>\n      </dl>\n    </section>\n    <section class=\"suite\">\n      <h1>utils.parseLinks(str)</h1>\n      <dl>\n        <dt>should parse links</dt>\n        <dd><pre><code>const string_ =\n  &#x27;&#x3C;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x3E;; rel=&#x22;next&#x22;, &#x3C;https://api.github.com/repos/visionmedia/mocha/issues?page=5&#x3E;; rel=&#x22;last&#x22;&#x27;;\nconst returnValue = utils.parseLinks(string_);\nreturnValue.next.should.equal(\n  &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=2&#x27;\n);\nreturnValue.last.should.equal(\n  &#x27;https://api.github.com/repos/visionmedia/mocha/issues?page=5&#x27;\n);</code></pre></dd>\n      </dl>\n    </section>\n-------------------|---------|----------|---------|---------|---------------------------------------\nFile               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                     \n-------------------|---------|----------|---------|---------|---------------------------------------\nAll files          |   93.42 |     83.3 |   89.67 |   93.92 |                                       \n src               |    92.5 |    83.83 |   91.83 |   93.84 |                                       \n  agent-base.js    |     100 |      100 |     100 |     100 |                                       \n  request-base.js  |   91.01 |     83.9 |   94.28 |   93.06 | ...21,262,316,501,525-533,579,757,768 \n  response-base.js |     100 |      100 |      75 |     100 |                                       \n  utils.js         |   92.85 |    71.42 |   85.71 |   91.66 | 94-98                                 \n src/node          |   93.61 |    83.12 |   87.36 |   93.75 |                                       \n  agent.js         |   89.79 |    66.66 |     100 |   88.63 | 39,43,47,51,101                       \n  http2wrapper.js  |      96 |     82.6 |   89.47 |   96.26 | 14,83,185-186                         \n  index.js         |   93.36 |    83.63 |   89.47 |   93.66 | ...,977,1182-1186,1220-1221,1275,1301 \n  response.js      |      90 |    83.33 |   55.55 |   89.79 | 78,86,94,120-121                      \n  unzip.js         |     100 |    92.85 |     100 |     100 | 47                                    \n src/node/parsers  |   97.61 |       75 |     100 |   97.61 |                                       \n  image.js         |     100 |      100 |     100 |     100 |                                       \n  index.js         |     100 |      100 |     100 |     100 |                                       \n  json.js          |     100 |       75 |     100 |     100 | 15                                    \n  text.js          |     100 |      100 |     100 |     100 |                                       \n  urlencoded.js    |      90 |      100 |     100 |      90 | 17                                    \n-------------------|---------|----------|---------|---------|---------------------------------------\n    </div>\n    <a href=\"http://github.com/ladjs/superagent\"><img style=\"position: absolute; top: 0; right: 0; border: 0;\" src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png\" alt=\"Fork me on GitHub\"></a>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js\"></script>\n    <script>\n      $('code').each(function(){\n        $(this).html(highlight($(this).text()));\n      });\n\n      function highlight(js) {\n        return js\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n          .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n          .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n      }\n    </script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js\"></script>\n    <script>\n      // Only use tocbot for main docs, not test docs\n      if (document.querySelector('#superagent')) {\n        tocbot.init({\n          // Where to render the table of contents.\n          tocSelector: '#menu',\n          // Where to grab the headings to build the table of contents.\n          contentSelector: '#content',\n          // Which headings to grab inside of the contentSelector element.\n          headingSelector: 'h2',\n          smoothScroll: false\n        });\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/zh_CN/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css\">\n    <link rel=\"stylesheet\" href=\"../style.css\">\n  </head>\n  <body>\n    <ul id=\"menu\"></ul>\n    <div id=\"content\">\n<h1 id=\"superagent\">SuperAgent</h1>\n<p>SuperAgent是轻量级的渐进式ajax API，具有灵活性、可读性和较低的学习曲线。 它也适用于Node.js!  </p>\n<pre><code> request\n   .post(&#39;/api/pet&#39;)\n   .send({ name: &#39;Manny&#39;, species: &#39;cat&#39; })\n   .set(&#39;X-API-Key&#39;, &#39;foobar&#39;)\n   .set(&#39;Accept&#39;, &#39;application/json&#39;)\n   .then(res =&gt; {\n      alert(&#39;yay got &#39; + JSON.stringify(res.body));\n   });\n</code></pre>\n<h2 id=\"测试文档\">测试文档</h2>\n<p><a href=\"/\"><strong>English</strong></a></p>\n<p>下面的<a href=\"../test.html\">测试文档</a>是用<a href=\"https://mochajs.org/\">Mocha</a>的&quot;文档&quot;报告器生成的，并直接反映了测试套件。 这提供了额外的文档来源。  </p>\n<h2 id=\"基本请求\">基本请求</h2>\n<p>可以通过调用 <code>request</code> 对象上的适当方法来发起请求，然后调用 <code>.then()</code> ( 或 <code>.end()</code> 或 <a href=\"#promise-and-generator-support\"><code>await</code></a> )发送请求。例如一个简单的 <strong>GET</strong> 请求：</p>\n<pre><code> request\n   .get(&#39;/search&#39;)\n   .then(res =&gt; {\n      // res.body, res.headers, res.status\n   })\n   .catch(err =&gt; {\n      // err.message, err.response\n   });\n</code></pre>\n<p>HTTP 方法也可以作为字符串传递：<br>译者注：大小写皆可。</p>\n<pre><code>request(&#39;GET&#39;, &#39;/search&#39;).then(success, failure);\n</code></pre>\n<p>旧式回调也受支持，但不推荐使用。您可以调用 <code>.end()</code> <em>代替</em> <code>.then()</code>：</p>\n<pre><code>request(&#39;GET&#39;, &#39;/search&#39;).end(function(err, res){\n  if (res.ok) {}\n});\n</code></pre>\n<p>可以使用绝对 URL。在 Web 浏览器中，绝对 URL 仅在服务器实现 <a href=\"#cors\">CORS</a> 时才有效。</p>\n<pre><code> request\n   .get(&#39;https://example.com/search&#39;)\n   .then(res =&gt; {\n\n   });\n</code></pre>\n<p><strong>Node</strong> 客户端支持向 <a href=\"https://zh.wikipedia.org/wiki/Unix%E5%9F%9F%E5%A5%97%E6%8E%A5%E5%AD%97\">Unix 域套接字</a> 发出请求：</p>\n<pre><code>// pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n//在套接字路径中将 `%2F` 用作 `/`\ntry {\n  const res = await request\n    .get(&#39;http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search&#39;);\n  // res.body, res.headers, res.status\n} catch(err) {\n  // err.message, err.response\n}\n</code></pre>\n<p><strong>DELETE__、__HEAD__、__PATCH__、__POST</strong> 和 <strong>PUT</strong> 请求也可以使用，只需更改方法名称：</p>\n<pre><code>request\n  .head(&#39;/favicon.ico&#39;)\n  .then(res =&gt; {\n\n  });\n</code></pre>\n<p><strong>DELETE</strong> 也可以用 <code>.del()</code> 调用以与旧版 IE 兼容，其中 <code>delete</code> 是保留字。</p>\n<p>HTTP 方法默认为 __GET__，因此如果您愿意，以下代码是有效的：</p>\n<pre><code> request(&#39;/search&#39;, (err, res) =&gt; {\n\n });\n</code></pre>\n<h2 id=\"使用-http-2\">使用 HTTP/2</h2>\n<p>要使用 HTTP/2 协议（没有 HTTP/1.x 后备），请使用 <code>.http2()</code> 方法。</p>\n<pre><code class=\"language-javascript\">    const request = require(&#39;superagent&#39;);\n    const res = await request\n      .get(&#39;https://example.com/h2&#39;)\n      .http2();\n</code></pre>\n<h2 id=\"设置请求头字段\">设置请求头字段</h2>\n<p>设置请求头字段很简单，调用 <code>.set()</code> 时传入字段名称和值：</p>\n<pre><code> request\n   .get(&#39;/search&#39;)\n   .set(&#39;API-Key&#39;, &#39;foobar&#39;)\n   .set(&#39;Accept&#39;, &#39;application/json&#39;)\n   .then(callback);\n</code></pre>\n<p>您还可以在一次调用中传入一个对象来设置多个字段：</p>\n<pre><code> request\n   .get(&#39;/search&#39;)\n   .set({ &#39;API-Key&#39;: &#39;foobar&#39;, Accept: &#39;application/json&#39; })\n   .then(callback);\n</code></pre>\n<h2 id=\"get-请求\"><code>GET</code> 请求</h2>\n<p><code>.query()</code> 方法接受对象，当与 <strong>GET</strong> 方法一起使用时将形成一个查询字符串。以下将产生路径 <code>/search?query=Manny&amp;range=1..5&amp;order=desc</code>。\n译者注：<code>.query()</code> 方法的参数不需要提前进行url编码。</p>\n<pre><code> request\n   .get(&#39;/search&#39;)\n   .query({ query: &#39;Manny&#39; })\n   .query({ range: &#39;1..5&#39; })\n   .query({ order: &#39;desc&#39; })\n   .then(res =&gt; {\n\n   });\n</code></pre>\n<p>或传入单个对象：</p>\n<pre><code>request\n  .get(&#39;/search&#39;)\n  .query({ query: &#39;Manny&#39;, range: &#39;1..5&#39;, order: &#39;desc&#39; })\n  .then(res =&gt; {\n\n  });\n</code></pre>\n<p><code>.query()</code> 方法也可以接受字符串。</p>\n<pre><code>  request\n    .get(&#39;/querystring&#39;)\n    .query(&#39;search=Manny&amp;range=1..5&#39;)\n    .then(res =&gt; {\n\n    });\n</code></pre>\n<p>或者一个个加入：</p>\n<pre><code>  request\n    .get(&#39;/querystring&#39;)\n    .query(&#39;search=Manny&#39;)\n    .query(&#39;range=1..5&#39;)\n    .then(res =&gt; {\n\n    });\n</code></pre>\n<h2 id=\"head-请求\"><code>HEAD</code> 请求</h2>\n<p>您还可以对 <strong>HEAD</strong> 请求使用 .query() 方法。以下将生成路径 <code>/users?email=joe@smith.com</code>。</p>\n<pre><code>  request\n    .head(&#39;/users&#39;)\n    .query({ email: &#39;joe@smith.com&#39; })\n    .then(res =&gt; {\n\n    });\n</code></pre>\n<h2 id=\"post--put-请求\"><code>POST</code> / <code>PUT</code> 请求</h2>\n<p>一个典型的 JSON <strong>POST</strong> 请求可能如下所示，我们适当地设置 <code>Content-Type</code> 请求头字段，并&quot;写入&quot;一些数据，在本例中只是一个 JSON 字符串。</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n    .send(&#39;{&quot;name&quot;:&quot;tj&quot;,&quot;pet&quot;:&quot;tobi&quot;}&#39;)\n    .then(callback)\n    .catch(errorCallback)\n</code></pre>\n<p>由于 JSON 无疑是最常见的，所以它是 <em>默认</em> 的！下面的例子与前面的例子是等价的。</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .send({ name: &#39;tj&#39;, pet: &#39;tobi&#39; })\n    .then(callback, errorCallback)\n</code></pre>\n<p>或者调用多个 <code>.send()</code>：</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .send({ name: &#39;tj&#39; })\n    .send({ pet: &#39;tobi&#39; })\n    .then(callback, errorCallback)\n</code></pre>\n<p>默认情况下，发送字符串会将 <code>Content-Type</code> 设置为 <code>application/x-www-form-urlencoded</code>，多个调用将用 <code>&amp;</code> 连接，这里产生 <code>name=tj&amp;pet=tobi</code>：</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .send(&#39;name=tj&#39;)\n    .send(&#39;pet=tobi&#39;)\n    .then(callback, errorCallback);\n</code></pre>\n<p>SuperAgent 格式是可扩展的，但默认情况下支持 &quot;json&quot; 和 &quot;form&quot;。要将数据作为 <code>application/x-www-form-urlencoded</code> 发送，只需在调用 <code>.type()</code> 时传入 &quot;form&quot;，默认为 &quot;json&quot;。此 <strong>POST</strong> 请求的请求体将是 &quot;name=tj&amp;pet=tobi&quot;。</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .type(&#39;form&#39;)\n    .send({ name: &#39;tj&#39; })\n    .send({ pet: &#39;tobi&#39; })\n    .then(callback, errorCallback)\n</code></pre>\n<p>还支持发送 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/FormData\"><code>FormData</code></a> 对象。以下示例将 <strong>POST</strong> 请求由 id=&quot;myForm&quot; 标识的 HTML 表单的内容：</p>\n<pre><code>  request.post(&#39;/user&#39;)\n    .send(new FormData(document.getElementById(&#39;myForm&#39;)))\n    .then(callback, errorCallback)\n</code></pre>\n<h2 id=\"设置-content-type\">设置 <code>Content-Type</code></h2>\n<p>显而易见的解决方案是使用 <code>.set()</code> 方法：</p>\n<pre><code> request.post(&#39;/user&#39;)\n   .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n</code></pre>\n<p><code>.type()</code> 方法也可以作为简写，接受带有类型/子类型的规范化 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types\">MIME 类型</a> 名称，或者只是扩展名，例如&quot;xml&quot;、&quot;json&quot;、&quot;png&quot;等：</p>\n<pre><code> request.post(&#39;/user&#39;)\n   .type(&#39;application/json&#39;)\n\n request.post(&#39;/user&#39;)\n   .type(&#39;json&#39;)\n\n request.post(&#39;/user&#39;)\n   .type(&#39;png&#39;)\n</code></pre>\n<h2 id=\"序列化请求体\">序列化请求体</h2>\n<p>SuperAgent 将自动序列化 JSON 和表单。您也可以为其他类型设置自动序列化：</p>\n<pre><code class=\"language-js\">request.serialize[&#39;application/xml&#39;] = function (obj) {\n    return &#39;从obj生成的字符串&#39;;\n};\n\n// 接下来，内容类型为 &quot;application/xml&quot; 的所有请求都将自动序列化\n</code></pre>\n<p>如果您想以自定义格式发送 数据体(payload)，您可以根据每个请求将内置序列化替换为 <code>.serialize()</code> 方法：</p>\n<pre><code class=\"language-js\">request\n    .post(&#39;/user&#39;)\n    .send({foo: &#39;bar&#39;})\n    .serialize(obj =&gt; {\n        return &#39;从obj生成的字符串&#39;;\n    });\n</code></pre>\n<h2 id=\"重试请求\">重试请求</h2>\n<p>如果请求暂时失败或可能是网络连接不稳定造成的失败，且当给定 <code>.retry()</code> 方法时，SuperAgent 将自动重试请求。</p>\n<p>此方法有两个可选参数：重试次数（默认为 <code>1</code>）和回调函数。它在每次重试之前调用 callback(err, res) 。回调可以返回 <code>true</code>/<code>false</code> 以控制是否应重试请求（但始终应该用最大重试次数）。\n     request\n       .get(&#39;<a href=\"https://example.com/search&#39;\">https://example.com/search&#39;</a>)\n       .retry(2) // 或者：\n       .retry(2, callback) // 二选一\n       .then(finished);\n       .catch(failed);</p>\n<p><code>.retry()</code> 仅用于<a href=\"https://baike.baidu.com/item/%E5%B9%82%E7%AD%89/8600688?fr=aladdin\"><em>幂等</em></a>请求（即到达服务器的多个请求不会导致重复购买等不良副作用）。</p>\n<p>默认情况下会尝试所有请求方法（这意味着如果您不希望重试 POST 请求，则需要传递自定义的重试回调函数）。</p>\n<p>默认情况下会重试以下状态代码：</p>\n<ul>\n<li><code>408</code></li>\n<li><code>413</code></li>\n<li><code>429</code></li>\n<li><code>500</code></li>\n<li><code>502</code></li>\n<li><code>503</code></li>\n<li><code>504</code></li>\n<li><code>521</code></li>\n<li><code>522</code></li>\n<li><code>524</code></li>\n</ul>\n<p>默认情况下会重试以下错误代码：</p>\n<ul>\n<li><code>&#39;ETIMEDOUT&#39;</code></li>\n<li><code>&#39;ECONNRESET&#39;</code></li>\n<li><code>&#39;EADDRINUSE&#39;</code></li>\n<li><code>&#39;ECONNREFUSED&#39;</code></li>\n<li><code>&#39;EPIPE&#39;</code></li>\n<li><code>&#39;ENOTFOUND&#39;</code></li>\n<li><code>&#39;ENETUNREACH&#39;</code></li>\n<li><code>&#39;EAI_AGAIN&#39;</code></li>\n</ul>\n<h2 id=\"设置-accept\">设置 Accept</h2>\n<p>与 <code>.type()</code> 方法类似，也可以通过简写方法 <code>.accept()</code> 设置 <code>Accept</code> 请求头。方便起见，其中还引用了 <code>request.types</code>，允许您将完整的规范化 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types\">MIME 类型</a> 名称指定为<code>类型/子类型</code>，或将扩展后缀形式指定为&quot;xml&quot;、&quot;json&quot;、&quot;png&quot;等：</p>\n<pre><code> request.get(&#39;/user&#39;)\n   .accept(&#39;application/json&#39;)\n\n request.get(&#39;/user&#39;)\n   .accept(&#39;json&#39;)\n\n request.post(&#39;/user&#39;)\n   .accept(&#39;png&#39;)\n</code></pre>\n<h3 id=\"facebook-和-accept-json\">Facebook 和 Accept JSON</h3>\n<p>如果您正在调用 Facebook 的 API，请务必在您的请求中发送 <code>Accept: application/json</code> 请求头。如果你不这样做，Facebook 会回复 <code>Content-Type: text/javascript; charset=UTF-8</code>，SuperAgent 将不会解析，因此 <code>res.body</code> 将是未定义的。您可以使用 <code>req.accept(&#39;json&#39;)</code> 或 <code>req.header(&#39;Accept&#39;, &#39;application/json&#39;)</code> 来执行此操作。有关详细信息，请参阅 <a href=\"https://github.com/ladjs/superagent/issues/1078\">issue 1078</a>。</p>\n<h2 id=\"查询字符串query-strings\">查询字符串(Query strings)</h2>\n<p><code>req.query(obj)</code> 是一种可用于构建查询字符串的方法。例如在 <strong>POST</strong> 上增加 <code>?format=json&amp;dest=/login</code>：</p>\n<pre><code>request\n  .post(&#39;/&#39;)\n  .query({ format: &#39;json&#39; })\n  .query({ dest: &#39;/login&#39; })\n  .send({ post: &#39;data&#39;, here: &#39;wahoo&#39; })\n  .then(callback);\n</code></pre>\n<p>默认情况下，查询字符串不按任何特定顺序组装。可以使用 <code>req.sortQuery()</code> 启用 ASCIIbetically 排序的查询字符串。您还可以使用 <code>req.sortQuery(myComparisonFn)</code> 提供自定义排序比较函数。比较函数应该接受 2 个参数并返回一个负/零/正整数。</p>\n<pre><code class=\"language-js\"> // 默认顺序\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery()\n   .then(callback)\n\n // 自定义排序函数\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery((a, b) =&gt; a.length - b.length)\n   .then(callback)\n</code></pre>\n<h2 id=\"tls-选项\">TLS 选项</h2>\n<p>在 Node.js 中，SuperAgent 支持配置 HTTPS 请求的方法：</p>\n<ul>\n<li><code>.ca()</code>: 将 CA 证书设置为信任</li>\n<li><code>.cert()</code>: 设置客户端证书链</li>\n<li><code>.key()</code>: 设置客户端私钥</li>\n<li><code>.pfx()</code>: 设置客户端 PFX 或 PKCS12 编码的私钥和证书链</li>\n<li><code>.disableTLSCerts()</code>: 不拒绝过期或无效的 TLS 证书。在内部设置 <code>rejectUnauthorized=true</code>。<em>请注意，此方法允许中间人攻击。</em></li>\n</ul>\n<p>有关更多信息，请参阅 Node.js <a href=\"http://nodejs.cn/api/https.html#httpsrequesturl-options-callback\">https.request 文档</a>。</p>\n<pre><code class=\"language-js\">var key = fs.readFileSync(&#39;key.pem&#39;),\n    cert = fs.readFileSync(&#39;cert.pem&#39;);\n\nrequest\n  .post(&#39;/client-auth&#39;)\n  .key(key)\n  .cert(cert)\n  .then(callback);\n</code></pre>\n<pre><code class=\"language-js\">var ca = fs.readFileSync(&#39;ca.cert.pem&#39;);\n\nrequest\n  .post(&#39;https://localhost/private-ca-server&#39;)\n  .ca(ca)\n  .then(res =&gt; {});\n</code></pre>\n<h2 id=\"解析响应体\">解析响应体</h2>\n<p>SuperAgent将为您解析已知的响应主体数据，目前支持<code>application/x-www-form-urlencoded</code>，<code>application/json</code>，以及<code>multipart/form data</code>。您可以设置自动解析其他响应主体数据：</p>\n<pre><code class=\"language-js\">//浏览器\nrequest.parse[&#39;application/xml&#39;] = function (str) {\n    return {&#39;object&#39;: &#39;从str解析的&#39;};\n};\n\n//node\nrequest.parse[&#39;application/xml&#39;] = function (res, cb) {\n    //解析响应文本并在此处设置res.body\n\n    cb(null, res);\n};\n\n//接下来，将自动解析 &#39;application/xml&#39; 类型的响应\n</code></pre>\n<p>您可以使用 <code>.buffer(true).parse(fn)</code> 方法设置自定义解析器（优先于内置解析器）。如果未启用响应缓冲 (<code>.buffer(false)</code>)，则将触发<code>响应(response)</code>事件而无需等待正文解析器完成，因此 <code>response.body</code> 将不可用。</p>\n<h3 id=\"json--urlencoded\">JSON / Urlencoded</h3>\n<p>属性 <code>res.body</code> 是解析后的对象，例如，如果请求以 JSON 字符串 &#39;{&quot;user&quot;:{&quot;name&quot;:&quot;tobi&quot;}}&#39; 响应，则 <code>res.body.user.name</code> 将为 &quot;tobi&quot; .同样，&quot;user[name]=tobi&quot; 的 x-www-form-urlencoded 值将产生相同的结果。仅支持一级嵌套。如果您需要更复杂的数据，请改为发送 JSON。</p>\n<p>通过重复的键发送数组。 <code>.send({color: [&#39;red&#39;,&#39;blue&#39;]})</code> 会发送 <code>color=red&amp;color=blue</code>。如果您希望数组键的名称中包含 <code>[]</code>，您必须自己添加它，因为 SuperAgent 不会自动添加它。</p>\n<h3 id=\"multipart\">Multipart</h3>\n<p>Node 客户端通过 <a href=\"https://github.com/felixge/node-formidable\">Formidable</a> 模块支持 _multipart/form-data_。解析 multipart 响应时，对象 <code>res.files</code> 也可供您使用。例如，假设一个请求使用以下 multipart 请求体进行响应：</p>\n<pre><code>--whoop\nContent-Disposition: attachment; name=&quot;image&quot;; filename=&quot;tobi.png&quot;\nContent-Type: image/png\n\n... data here ...\n--whoop\nContent-Disposition: form-data; name=&quot;name&quot;\nContent-Type: text/plain\n\nTobi\n--whoop--\n</code></pre>\n<p><code>res.body.name</code>的值将为 &quot;Tobi&quot;，并且 <code>res.files.image</code> 将作为包含磁盘路径、文件名和其他属性的 <code>File</code> 对象。</p>\n<h3 id=\"二进制数据\">二进制数据</h3>\n<p>在浏览器中，您可以使用 <code>.responseType(&#39;blob&#39;)</code> 来请求处理二进制响应体。在 node.js 中运行时不需要此 API。此方法支持的参数值为</p>\n<ul>\n<li><code>&#39;blob&#39;</code> 赋值给 XmlHTTPRequest 的 <code>responseType</code> 属性</li>\n<li><code>&#39;arraybuffer&#39;</code> 赋值给 XmlHTTPRequest 的 responseType 属性</li>\n</ul>\n<pre><code class=\"language-js\">req.get(&#39;/binary.data&#39;)\n  .responseType(&#39;blob&#39;)\n  .then(res =&gt; {\n    // res.body 将是浏览器原生 Blob 类型\n  });\n</code></pre>\n<p>有关更多信息，请参阅 Mozilla 开发人员网络 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/responseType\">xhr.responseType 文档</a>。</p>\n<h2 id=\"响应属性\">响应属性</h2>\n<p>在 <code>Response</code> 对象上设置了许多有用的标志和属性，包括响应文本、解析的响应正文、响应头字段、状态标志等等。</p>\n<h3 id=\"响应文本\">响应文本</h3>\n<p><code>res.text</code> 属性包含未解析的响应正文字符串。此属性始终存在于客户端 API 中，并且仅当默认情况下节点的 mime 类型与 &quot;text/<em>&quot;、&quot;</em>/json&quot; 或 &quot;x-www-form-urlencoded&quot; 匹配时。原因是为了节省内存，因为缓冲大型正文（例如 multipart 文件或图像）的文本效率极低。要强制缓冲，请参阅&quot;<a href=\"#%E7%BC%93%E5%86%B2%E5%93%8D%E5%BA%94\">缓冲响应</a>&quot;部分。</p>\n<h3 id=\"响应体\">响应体</h3>\n<p>就像 SuperAgent 可以自动序列化请求数据一样，它也可以自动解析响应体。为 Content-Type 定义解析器时，会对其进行解析，默认情况下包括 &quot;application/json&quot; 和 &quot;application/x-www-form-urlencoded&quot;。然后可以通过 <code>res.body</code> 获得解析的对象。</p>\n<h3 id=\"响应头字段\">响应头字段</h3>\n<p><code>res.header</code> 包含已解析的响应头字段的对象，字段名称小写，就像 node 做的一样。例如 <code>res.header[&#39;content-length&#39;]</code>。</p>\n<h3 id=\"响应内容类型content-type\">响应内容类型(Content-Type)</h3>\n<p>Content-Type 响应头是特殊情况，提供 <code>res.type</code>，它没有字符集（也可以有）。例如，&quot;text/html; charset=utf8&quot; 的 <code>Content-Type</code> 将提供 &quot;text/html&quot; 作为 <code>res.type</code>，然后 <code>res.charset</code> 属性将包含 &quot;utf8&quot;。</p>\n<h3 id=\"响应状态\">响应状态</h3>\n<p>响应状态标志有助于确定请求是否成功，以及其他有用的信息，使 SuperAgent 成为与 RESTful Web 服务交互的理想选择。这些标志当前定义为：</p>\n<pre><code> var type = status / 100 | 0;\n\n // status / class\n res.status = status;\n res.statusType = type;\n\n // basics\n res.info = 1 == type;\n res.ok = 2 == type;\n res.clientError = 4 == type;\n res.serverError = 5 == type;\n res.error = 4 == type || 5 == type;\n\n // 语法糖\n res.accepted = 202 == status;\n res.noContent = 204 == status || 1223 == status;\n res.badRequest = 400 == status;\n res.unauthorized = 401 == status;\n res.notAcceptable = 406 == status;\n res.notFound = 404 == status;\n res.forbidden = 403 == status;\n</code></pre>\n<h2 id=\"中止请求\">中止请求</h2>\n<p>要中止请求，只需调用 <code>req.abort()</code> 方法。</p>\n<h2 id=\"超时设定\">超时设定</h2>\n<p>有时网络和服务器会 &quot;卡住&quot; 并且在接受请求后从不响应。设置超时以避免请求永远等待。</p>\n<ul>\n<li><p><code>req.timeout({deadline:ms})</code> 或 <code>req.timeout(ms)</code>（其中 <code>ms</code> 是毫秒数 &gt; 0）设置完成整个请求（包括所有上传、重定向、服务器处理时间）的最后期限。如果在这段时间内没有完全下载响应，则请求将被中止。</p>\n</li>\n<li><p><code>req.timeout({response:ms})</code> 设置等待第一个字节从服务器到达的最长时间，但它不限制整个下载需要多长时间。响应超时应该至少比服务器响应的时间长几秒钟，因为它还包括进行 DNS 查找、TCP/IP 和 TLS 连接的时间，以及上传请求数据的时间。</p>\n</li>\n</ul>\n<p>您应该同时使用 <code>deadline</code> 和 <code>response</code> 超时。通过这种方式，您可以使用较短的响应超时来快速检测无响应的网络，并使用较长的截止时间来为缓慢但可靠的网络上的下载留出时间。请注意，这两个计时器都限制了允许<em>上传</em>附件的时间。如果您要上传文件，请使用长超时。</p>\n<pre><code>request\n  .get(&#39;/big-file?network=slow&#39;)\n  .timeout({\n    response: 5000,  // 等待 5 秒让服务器开始发送\n    deadline: 60000, // 但允许文件用 1 分钟完成加载。\n  })\n  .then(res =&gt; {\n      /* 及时响应 */\n    }, err =&gt; {\n      if (err.timeout) { /* 超时! */ } else { /* 其他错误 */ }\n  });\n</code></pre>\n<p>超时错误有个 <code>.timeout</code> 属性。</p>\n<h2 id=\"验证\">验证</h2>\n<p>在 Node 和浏览器中都可以通过 <code>.auth()</code> 方法进行身份验证：</p>\n<pre><code>request\n  .get(&#39;http://local&#39;)\n  .auth(&#39;tobi&#39;, &#39;learnboost&#39;)\n  .then(callback);\n</code></pre>\n<p>在 <em>Node</em> 客户端中，基本身份验证可以在 URL 中写成 &quot;user:pass&quot;：</p>\n<pre><code>request.get(&#39;http://tobi:learnboost@local&#39;).then(callback);\n</code></pre>\n<p>默认情况下，仅使用<code>基本(Basic)</code>身份验证。在浏览器中，您可以添加 <code>{type:&#39;auto&#39;}</code> 以启用浏览器中内置的所有方法（Digest、NTLM 等）：</p>\n<pre><code>request.auth(&#39;digest&#39;, &#39;secret&#39;, {type:&#39;auto&#39;})\n</code></pre>\n<p><code>auth</code> 方法还支持一种<code>承载类型</code>，以指定基于令牌的身份验证：</p>\n<pre><code>request.auth(&#39;my_token&#39;, { type: &#39;bearer&#39; })\n</code></pre>\n<h2 id=\"跟随重定向\">跟随重定向</h2>\n<p>默认情况下将跟随最多 5 个重定向，但是您可以使用 <code>res.redirects(n)</code> 方法指定它：</p>\n<pre><code>const response = await request.get(&#39;/some.png&#39;).redirects(2);\n</code></pre>\n<p>超出限制的重定向被视为错误。使用 <code>.ok(res =&gt; res.status &lt; 400)</code> 将它们读取为成功响应。</p>\n<h2 id=\"全局状态代理程序\">全局状态代理程序</h2>\n<h3 id=\"保存-cookie\">保存 cookie</h3>\n<p>在 Node 中 SuperAgent 默认不保存 cookie，但您可以使用 <code>.agent()</code> 方法创建保存 cookie 的 SuperAgent 副本。每个副本都有一个单独的 cookie 储存器。</p>\n<pre><code>const agent = request.agent();\nagent\n  .post(&#39;/login&#39;)\n  .then(() =&gt; {\n    return agent.get(&#39;/cookied-page&#39;);\n  });\n</code></pre>\n<p>在浏览器中，cookie 由浏览器自动管理，因此 <code>.agent()</code> 不会隔离 cookie。</p>\n<h3 id=\"多个请求的默认选项\">多个请求的默认选项</h3>\n<p>代理程序上调用的常规请求方法将用作该代理发出的所有请求的默认值。</p>\n<pre><code>const agent = request.agent()\n  .use(plugin)\n  .auth(shared);\n\nawait agent.get(&#39;/with-plugin-and-auth&#39;); // 带有插件和身份验证\nawait agent.get(&#39;/also-with-plugin-and-auth&#39;); // 也带有插件和身份验证\n</code></pre>\n<p>代理可以用来设置默认值的完整方法列表是：<code>use</code>、 <code>on</code>、 <code>once</code>、 <code>set</code>、 <code>query</code>、 <code>type</code>、 <code>accept</code>、 <code>auth</code>、 <code>withCredentials</code>、 <code>sortQuery</code>、 <code>retry</code>、 <code>ok</code>、 <code>redirects</code>、 <code>timeout</code>、 <code>buffer</code>、 <code>serialize</code>、 <code>parse</code>、 <code>ca</code>、 <code>key</code>、 <code>pfx</code>、 <code>cert</code>.</p>\n<h2 id=\"管道数据\">管道数据</h2>\n<p>Node 客户端允许您通过管道将数据传入和传出请求。请注意，使用 <code>.pipe()</code> <strong>代替</strong> <code>.end()/.then()</code> 方法。</p>\n<p>管道文件的内容作为请求的例子：</p>\n<pre><code>const request = require(&#39;superagent&#39;);\nconst fs = require(&#39;fs&#39;);\n\nconst stream = fs.createReadStream(&#39;path/to/my.json&#39;);\nconst req = request.post(&#39;/somewhere&#39;);\nreq.type(&#39;json&#39;);\nstream.pipe(req);\n</code></pre>\n<p>请注意，当您通过管道发送请求时，superagent 使用<a href=\"https://baike.baidu.com/item/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81/8359216?fr=aladdin\">分块传输编码</a>发送管道数据，并非所有服务器（例如 Python WSGI 服务器）都支持。</p>\n<p>或将响应传送到文件：</p>\n<pre><code>const stream = fs.createWriteStream(&#39;path/to/my.json&#39;);\nconst req = request.get(&#39;/some.json&#39;);\nreq.pipe(stream);\n</code></pre>\n<p> 不能混合使用管道和回调函数或 promises。请注意，您<strong>不应</strong>尝试通过管道传输 <code>.end()</code> 或 <code>Response</code> 对象的结果：</p>\n<pre><code>// 别特么这么写：\nconst stream = getAWritableStream();\nconst req = request\n  .get(&#39;/some.json&#39;)\n  // BAD: 这会将无用信息管道传输到流中并以意想不到的方式失败\n  .end((err, this_does_not_work) =&gt; this_does_not_work.pipe(stream))\nconst req = request\n  .get(&#39;/some.json&#39;)\n  .end()\n  // BAD: 这也不支持，调用 .end 之后调用 .pipe。\n  .pipe(nope_its_too_late);\n</code></pre>\n<p>在 superagent 的<a href=\"https://github.com/ladjs/superagent/issues/1188\">未来版本</a>中，对 <code>pipe()</code> 的不当调用将失败。</p>\n<h2 id=\"多部分请求\">多部分请求</h2>\n<p>SuperAgent 也非常适合 <em>构建</em> 它提供方法 <code>.attach()</code> 和 <code>.field()</code> 的多部分请求。</p>\n<p>当您使用 <code>.field()</code> 或 <code>.attach()</code> 时，您不能使用 <code>.send()</code> 并且您<em>不能</em>设置 <code>Content-Type</code>（将为您设置正确的类型）。</p>\n<h3 id=\"附加文件\">附加文件</h3>\n<p>要发送文件，请使用 <code>.attach(name, [file], [options])</code>。您可以通过多次调用 <code>.attach</code> 来附加多个文件。参数是：</p>\n<ul>\n<li><code>name</code> — form 表单中的字段名。</li>\n<li><code>file</code> — 带有文件路径的字符串或 <code>Blob/Buffer</code> 对象。</li>\n<li><code>options</code> — （可选）自定义文件名的字符串或 <code>{filename: string}</code> 对象。在 Node 中也支持 <code>{contentType: &#39;mime/type&#39;}</code>。在浏览器中创建一个具有适当类型的 <code>Blob</code>。</li>\n</ul>\n<br>\n\n<pre><code>request\n  .post(&#39;/upload&#39;)\n  .attach(&#39;image1&#39;, &#39;path/to/felix.jpeg&#39;)\n  .attach(&#39;image2&#39;, imageBuffer, &#39;luna.jpeg&#39;)\n  .field(&#39;caption&#39;, &#39;My cats&#39;)\n  .then(callback);\n</code></pre>\n<h3 id=\"字段值\">字段值</h3>\n<p>与 HTML 中的表单字段非常相似，您可以使用 <code>.field(name, value)</code> 和 <code>.field({name: value})</code> 设置字段值。假设您想上传一些带有您的姓名和电子邮件的图片，您的请求可能如下所示：</p>\n<pre><code> request\n   .post(&#39;/upload&#39;)\n   .field(&#39;user[name]&#39;, &#39;Tobi&#39;)\n   .field(&#39;user[email]&#39;, &#39;tobi@learnboost.com&#39;)\n   .field(&#39;friends[]&#39;, [&#39;loki&#39;, &#39;jane&#39;])\n   .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n   .then(callback);\n</code></pre>\n<h2 id=\"压缩\">压缩</h2>\n<p>node 客户端支持压缩过的响应，最重要的是，您无需执行任何操作！它就能用。</p>\n<h2 id=\"缓冲响应\">缓冲响应</h2>\n<p>要强制将响应主体缓冲为 <code>res.text</code>，您可以调用 <code>req.buffer()</code>。要取消对文本响应（例如 &quot;text/plain&quot;、&quot;text/html&quot; 等）的默认缓冲，您可以调用 <code>req.buffer(false)</code>。 </p>\n<p>当缓冲提供 <code>res.buffered</code> 标志时，您可以使用它在同一个回调中处理缓冲和非缓冲响应。</p>\n<h2 id=\"cors\">CORS</h2>\n<p>出于安全原因，浏览器将阻止跨域请求，除非服务器选择使用 CORS 标头。浏览器还会发出额外的 <strong>OPTIONS</strong> 请求来检查服务器允许哪些 HTTP 标头和方法。<a href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS\">阅读有关 CORS 的更多信息</a>。</p>\n<p><code>.withCredentials()</code> 方法支持从源发送 cookie，但仅当 Access-Control-Allow-Origin <em>不是</em> 通配符 (&quot;*&quot;) 且 <code>Access-Control-Allow-Credentials</code> 为 &quot;true&quot; 时。</p>\n<pre><code>request\n  .get(&#39;https://api.example.com:4001/&#39;)\n  .withCredentials()\n  .then(res =&gt; {\n    assert.equal(200, res.status);\n    assert.equal(&#39;tobi&#39;, res.text);\n  })\n</code></pre>\n<h2 id=\"错误处理\">错误处理</h2>\n<p>您的回调函数将始终传递两个参数：错误和响应。如果没有发生错误，第一个参数将为<code>null</code>：</p>\n<pre><code>request\n .post(&#39;/upload&#39;)\n .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n .then(res =&gt; {\n\n });\n</code></pre>\n<p>还会触发&quot;错误&quot;事件，您可以监听：</p>\n<pre><code>request\n  .post(&#39;/upload&#39;)\n  .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n  .on(&#39;error&#39;, handle)\n  .then(res =&gt; {\n\n  });\n</code></pre>\n<p>请注意，<strong>默认情况下，superagent 会考虑 4xx 和 5xx 响应（以及未处理的 3xx 响应）视为错误</strong>。例如，如果您收到 <code>304 Not modified</code>、<code>403 Forbidden</code> 或 <code>500 Internal server</code> 错误响应，则此状态信息将通过 <code>err.status</code> 提供。来自此类响应的错误还包含一个 <code>err.response</code> 字段，其中包含&quot;<a href=\"#%E5%93%8D%E5%BA%94%E5%B1%9E%E6%80%A7\">响应属性</a>&quot;中提到的所有属性。该库以这种方式运行以处理需要成功响应并将 HTTP 错误状态代码视为错误的常见情况，同时仍允许围绕特定错误条件进行自定义逻辑。</p>\n<p>网络故障、超时和其他不产生响应的错误将不包含 <code>err.status</code> 或 <code>err.response</code> 字段。</p>\n<p>如果您希望处理 404 或其他 HTTP 错误响应，您可以查询 <code>err.status</code> 属性。当发生 HTTP 错误（4xx 或 5xx 响应）时， <code>res.error</code> 属性是一个 <code>Error</code> 对象，这允许您执行以下检查：</p>\n<pre><code>if (err &amp;&amp; err.status === 404) {\n  alert(&#39;oh no &#39; + res.body.message);\n}\nelse if (err) {\n  // 所有其他需要处理的错误类型\n}\n</code></pre>\n<p>或者，您可以使用 <code>.ok(callback)</code> 方法来确定响应是否为错误。 <code>ok</code> 函数的回调函数获得响应，如果响应应该被解释为成功，则返回 true。</p>\n<pre><code>request.get(&#39;/404&#39;)\n  .ok(res =&gt; res.status &lt; 500)\n  .then(response =&gt; {\n    // 将 404 页面作为成功响应\n  })\n</code></pre>\n<h2 id=\"进度跟踪\">进度跟踪</h2>\n<p>SuperAgent 在上传和下载大文件时触发 <code>progress</code> 事件。</p>\n<pre><code>request.post(url)\n  .attach(&#39;field_name&#39;, file)\n  .on(&#39;progress&#39;, event =&gt; {\n    /* event的值：\n    {\n      direction: &quot;upload&quot; or &quot;download&quot;\n      percent: 0 to 100 // 如果文件大小未知，可能会没有\n      total: // 总文件大小，可能没有\n      loaded: // 到目前为止下载或上传的字节数\n    } */\n  })\n  .then()\n</code></pre>\n<h2 id=\"在本地主机上测试\">在本地主机上测试</h2>\n<h3 id=\"强制连接特定-ip-地址\">强制连接特定 IP 地址</h3>\n<p>在 Node.js 中，可以忽略 DNS 解析并使用 <code>.connect()</code> 方法将所有请求定向到特定 IP 地址。例如，此请求将转到 localhost 而不是 <code>example.com</code>：</p>\n<pre><code>const res = await request.get(&quot;http://example.com&quot;).connect(&quot;127.0.0.1&quot;);\n</code></pre>\n<p>因为请求可能被重定向，所以可以指定多个主机名和多个 IP，以及一个特殊的 <code>*</code> 作为后备（注意：不支持其他通配符）。请求将保留其 <code>Host</code> 请求头的原始值。</p>\n<pre><code>const res = await request.get(&quot;http://redir.example.com:555&quot;)\n  .connect({\n    &quot;redir.example.com&quot;: &quot;127.0.0.1&quot;, // redir.example.com:555 将使用 127.0.0.1:555\n    &quot;www.example.com&quot;: false, // 不覆盖这个；正常使用 DNS\n    &quot;mapped.example.com&quot;: { host: &quot;127.0.0.1&quot;, port: 8080}, // mapped.example.com:* 将使用 127.0.0.1:8080\n    &quot;*&quot;: &quot;proxy.example.com&quot;, // 所有其他请求都将发送到该主机\n  });\n</code></pre>\n<h3 id=\"忽略本地主机上损坏不安全的-https\">忽略本地主机上损坏/不安全的 HTTPS</h3>\n<p>在 Node.js 中，当 HTTPS 配置错误且不安全（例如，使用自签名证书而<em>不指定</em>自己的 <code>.ca()</code>）时，仍然可以通过调用 <code>.trustLocalhost()</code> 来允许对 <code>localhost</code> 的请求：</p>\n<pre><code>const res = await request.get(&quot;https://localhost&quot;).trustLocalhost()\n</code></pre>\n<p>与 <code>.connect(&quot;127.0.0.1&quot;)</code> 一起，这可用于强制将对任何域的 HTTPS 请求重新路由到 <code>localhost</code>。</p>\n<p>忽略本地主机上损坏的 HTTPS 通常是安全的，因为环回接口不会暴露给不受信任的网络。信任 <code>localhost</code> 可能会成为未来的默认设置。使用 <code>.trustLocalhost(false)</code> 强制检查 <code>127.0.0.1</code> 的可靠性。</p>\n<p>当向任何其他 IP 发出请求时，我们故意不支持禁用 HTTPS 安全性，因为这些选项最终被滥用为 HTTPS 问题的快速&quot;修复&quot;。您可以从 <a href=\"https://certbot.eff.org\">Let&#39;s Encrypt</a> 获得免费的 HTTPS 证书或设置您自己的 CA (<code>.ca(ca_public_pem)</code>) 以使您的自签名证书受信任。</p>\n<h2 id=\"promise-和生成器函数支持\">Promise 和生成器函数支持</h2>\n<p>SuperAgent 的请求是一个 &quot;thenable&quot; 对象(带有then方法的对象)，它与 JavaScript Promise 和 <code>async/await</code> 语法兼容。</p>\n<pre><code>const res = await request.get(url);\n</code></pre>\n<p>如果你使用 Promise，<strong>不要</strong>调用 <code>.end()</code> 或 <code>.pipe()</code>。任何使用 <code>.then()</code> 或 <code>await</code> 都会禁用所有其他使用请求的方式。 像 <a href=\"https://github.com/tj/co\">co</a> 这样的库或像 <a href=\"https://github.com/koajs/koa\">koa</a> 这样的 web 框架可以在任何 SuperAgent 方法上 <code>yield</code>：</p>\n<pre><code>const req = request\n  .get(&#39;http://local&#39;)\n  .auth(&#39;tobi&#39;, &#39;learnboost&#39;);\nconst res = yield req;\n</code></pre>\n<p>请注意，SuperAgent 期望全局 <code>Promise</code> 对象存在。您需要一个 polyfill 才能在 Internet Explorer 或 Node.js 0.10 中使用 Promise。</p>\n<h2 id=\"浏览器和-node-版本\">浏览器和 node 版本</h2>\n<p>SuperAgent 有两种实现：一种用于 Web 浏览器（使用 XHR），另一种用于 Node.JS（使用核心 http 模块）。默认情况下，Browserify 和 WebPack 将选择浏览器版本。 </p>\n<p>如果要使用 WebPack 为 Node.JS 编译代码，您<em>必须</em>在其配置中指定<a href=\"https://webpack.github.io/docs/configuration.html#target\">node target</a>。</p>\n<h3 id=\"在-electron-中使用浏览器版本\">在 electron 中使用浏览器版本</h3>\n<p><a href=\"https://electron.atom.io/\">Electron</a> 开发人员报告说，如果您希望使用浏览器版本的 SuperAgent 而不是 Node 版本，您可以 <code>require(&#39;superagent/superagent&#39;)</code>。这样您的请求将显示在 Chrome 开发者工具的&quot;网络(Network)&quot;选项卡中。请注意，自动化测试套件未涵盖此环境，也未得到官方支持。</p>\n<h2 id=\"使用代理发送请求\">使用代理发送请求</h2>\n<p>可以使用另一个作者的 <a href=\"https://www.npmjs.com/package/superagent-proxy\">superagent-proxy</a> 模块</p>\n<h2 id=\"翻译说明\">翻译说明</h2>\n<p>文档全部内容都是根据原英文文档翻译的，译者也没水平，所以如果有错误还请指出</p>\n    </div>\n    <a href=\"http://github.com/ladjs/superagent\"><img style=\"position: absolute; top: 0; right: 0; border: 0;\" src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png\" alt=\"Fork me on GitHub\"></a>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js\"></script>\n    <script>\n      $('code').each(function(){\n        $(this).html(highlight($(this).text()));\n      });\n\n      function highlight(js) {\n        return js\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n          .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n          .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n      }\n    </script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js\"></script>\n    <script>\n      // Only use tocbot for main docs, not test docs\n      if (document.querySelector('#superagent')) {\n        tocbot.init({\n          // Where to render the table of contents.\n          tocSelector: '#menu',\n          // Where to grab the headings to build the table of contents.\n          contentSelector: '#content',\n          // Which headings to grab inside of the contentSelector element.\n          headingSelector: 'h2',\n          smoothScroll: false\n        });\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/zh_CN/index.md",
    "content": "# SuperAgent\n\nSuperAgent是轻量级的渐进式ajax API，具有灵活性、可读性和较低的学习曲线。 它也适用于Node.js!  \n\n     request\n       .post('/api/pet')\n       .send({ name: 'Manny', species: 'cat' })\n       .set('X-API-Key', 'foobar')\n       .set('Accept', 'application/json')\n       .then(res => {\n          alert('yay got ' + JSON.stringify(res.body));\n       });\n\n## 测试文档 \n\n[**English**](/superagent/)\n\n下面的[测试文档](../test.html)是用[Mocha](https://mochajs.org/)的\"文档\"报告器生成的，并直接反映了测试套件。 这提供了额外的文档来源。  \n\n## 基本请求\n\n可以通过调用 `request` 对象上的适当方法来发起请求，然后调用 `.then()` ( 或 `.end()` 或 [`await`](#promise-and-generator-support) )发送请求。例如一个简单的 __GET__ 请求：\n\n     request\n       .get('/search')\n       .then(res => {\n          // res.body, res.headers, res.status\n       })\n       .catch(err => {\n          // err.message, err.response\n       });\n\nHTTP 方法也可以作为字符串传递：  \n译者注：大小写皆可。\n\n    request('GET', '/search').then(success, failure);\n\n旧式回调也受支持，但不推荐使用。您可以调用 `.end()` *代替* `.then()`：\n\n    request('GET', '/search').end(function(err, res){\n      if (res.ok) {}\n    });\n\n可以使用绝对 URL。在 Web 浏览器中，绝对 URL 仅在服务器实现 [CORS](#cors) 时才有效。\n\n     request\n       .get('https://example.com/search')\n       .then(res => {\n\n       });\n\n__Node__ 客户端支持向 [Unix 域套接字](https://zh.wikipedia.org/wiki/Unix%E5%9F%9F%E5%A5%97%E6%8E%A5%E5%AD%97) 发出请求：\n\n    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n    //在套接字路径中将 `%2F` 用作 `/`\n    try {\n      const res = await request\n        .get('http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search');\n      // res.body, res.headers, res.status\n    } catch(err) {\n      // err.message, err.response\n    }\n\n__DELETE__、__HEAD__、__PATCH__、__POST__ 和 __PUT__ 请求也可以使用，只需更改方法名称：\n\n    request\n      .head('/favicon.ico')\n      .then(res => {\n\n      });\n\n__DELETE__ 也可以用 `.del()` 调用以与旧版 IE 兼容，其中 `delete` 是保留字。\n\nHTTP 方法默认为 __GET__，因此如果您愿意，以下代码是有效的：\n\n     request('/search', (err, res) => {\n\n     });\n\n## 使用 HTTP/2\n\n要使用 HTTP/2 协议（没有 HTTP/1.x 后备），请使用 `.http2()` 方法。\n\n    const request = require('superagent');\n    const res = await request\n      .get('https://example.com/h2')\n      .http2();\n\n## 设置请求头字段\n\n设置请求头字段很简单，调用 `.set()` 时传入字段名称和值：\n\n     request\n       .get('/search')\n       .set('API-Key', 'foobar')\n       .set('Accept', 'application/json')\n       .then(callback);\n\n您还可以在一次调用中传入一个对象来设置多个字段：\n\n     request\n       .get('/search')\n       .set({ 'API-Key': 'foobar', Accept: 'application/json' })\n       .then(callback);\n\n## `GET` 请求\n\n`.query()` 方法接受对象，当与 __GET__ 方法一起使用时将形成一个查询字符串。以下将产生路径 `/search?query=Manny&range=1..5&order=desc`。\n译者注：`.query()` 方法的参数不需要提前进行url编码。\n\n     request\n       .get('/search')\n       .query({ query: 'Manny' })\n       .query({ range: '1..5' })\n       .query({ order: 'desc' })\n       .then(res => {\n\n       });\n\n或传入单个对象：\n\n    request\n      .get('/search')\n      .query({ query: 'Manny', range: '1..5', order: 'desc' })\n      .then(res => {\n\n      });\n\n`.query()` 方法也可以接受字符串。\n\n      request\n        .get('/querystring')\n        .query('search=Manny&range=1..5')\n        .then(res => {\n\n        });\n\n或者一个个加入：\n\n      request\n        .get('/querystring')\n        .query('search=Manny')\n        .query('range=1..5')\n        .then(res => {\n\n        });\n\n## `HEAD` 请求\n\n您还可以对 __HEAD__ 请求使用 .query() 方法。以下将生成路径 `/users?email=joe@smith.com`。\n\n      request\n        .head('/users')\n        .query({ email: 'joe@smith.com' })\n        .then(res => {\n\n        });\n\n## `POST` / `PUT` 请求\n\n一个典型的 JSON __POST__ 请求可能如下所示，我们适当地设置 `Content-Type` 请求头字段，并\"写入\"一些数据，在本例中只是一个 JSON 字符串。\n\n      request.post('/user')\n        .set('Content-Type', 'application/json')\n        .send('{\"name\":\"tj\",\"pet\":\"tobi\"}')\n        .then(callback)\n        .catch(errorCallback)\n\n由于 JSON 无疑是最常见的，所以它是 _默认_ 的！下面的例子与前面的例子是等价的。\n\n      request.post('/user')\n        .send({ name: 'tj', pet: 'tobi' })\n        .then(callback, errorCallback)\n\n或者调用多个 `.send()`：\n\n      request.post('/user')\n        .send({ name: 'tj' })\n        .send({ pet: 'tobi' })\n        .then(callback, errorCallback)\n\n默认情况下，发送字符串会将 `Content-Type` 设置为 `application/x-www-form-urlencoded`，多个调用将用 `&` 连接，这里产生 `name=tj&pet=tobi`：\n\n      request.post('/user')\n        .send('name=tj')\n        .send('pet=tobi')\n        .then(callback, errorCallback);\n\nSuperAgent 格式是可扩展的，但默认情况下支持 \"json\" 和 \"form\"。要将数据作为 `application/x-www-form-urlencoded` 发送，只需在调用 `.type()` 时传入 \"form\"，默认为 \"json\"。此 __POST__ 请求的请求体将是 \"name=tj&pet=tobi\"。\n\n      request.post('/user')\n        .type('form')\n        .send({ name: 'tj' })\n        .send({ pet: 'tobi' })\n        .then(callback, errorCallback)\n\n还支持发送 [`FormData`](https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/FormData) 对象。以下示例将 __POST__ 请求由 id=\"myForm\" 标识的 HTML 表单的内容：\n\n      request.post('/user')\n        .send(new FormData(document.getElementById('myForm')))\n        .then(callback, errorCallback)\n\n## 设置 `Content-Type`\n\n显而易见的解决方案是使用 `.set()` 方法：\n\n     request.post('/user')\n       .set('Content-Type', 'application/json')\n\n`.type()` 方法也可以作为简写，接受带有类型/子类型的规范化 [MIME 类型](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types) 名称，或者只是扩展名，例如\"xml\"、\"json\"、\"png\"等：\n\n     request.post('/user')\n       .type('application/json')\n\n     request.post('/user')\n       .type('json')\n\n     request.post('/user')\n       .type('png')\n\n## 序列化请求体\n\nSuperAgent 将自动序列化 JSON 和表单。您也可以为其他类型设置自动序列化：\n\n```js\nrequest.serialize['application/xml'] = function (obj) {\n    return '从obj生成的字符串';\n};\n\n// 接下来，内容类型为 \"application/xml\" 的所有请求都将自动序列化\n```\n如果您想以自定义格式发送 数据体(payload)，您可以根据每个请求将内置序列化替换为 `.serialize()` 方法：\n\n```js\nrequest\n    .post('/user')\n    .send({foo: 'bar'})\n    .serialize(obj => {\n        return '从obj生成的字符串';\n    });\n```\n## 重试请求\n\n如果请求暂时失败或可能是网络连接不稳定造成的失败，且当给定 `.retry()` 方法时，SuperAgent 将自动重试请求。\n\n此方法有两个可选参数：重试次数（默认为 `1`）和回调函数。它在每次重试之前调用 callback(err, res) 。回调可以返回 `true`/`false` 以控制是否应重试请求（但始终应该用最大重试次数）。\n     request\n       .get('https://example.com/search')\n       .retry(2) // 或者：\n       .retry(2, callback) // 二选一\n       .then(finished);\n       .catch(failed);\n\n`.retry()` 仅用于[*幂等*](https://baike.baidu.com/item/%E5%B9%82%E7%AD%89/8600688?fr=aladdin)请求（即到达服务器的多个请求不会导致重复购买等不良副作用）。\n\n默认情况下会尝试所有请求方法（这意味着如果您不希望重试 POST 请求，则需要传递自定义的重试回调函数）。\n\n默认情况下会重试以下状态代码：\n\n* `408`\n* `413`\n* `429`\n* `500`\n* `502`\n* `503`\n* `504`\n* `521`\n* `522`\n* `524`\n\n默认情况下会重试以下错误代码：\n\n* `'ETIMEDOUT'`\n* `'ECONNRESET'`\n* `'EADDRINUSE'`\n* `'ECONNREFUSED'`\n* `'EPIPE'`\n* `'ENOTFOUND'`\n* `'ENETUNREACH'`\n* `'EAI_AGAIN'`\n\n## 设置 Accept\n\n与 `.type()` 方法类似，也可以通过简写方法 `.accept()` 设置 `Accept` 请求头。方便起见，其中还引用了 `request.types`，允许您将完整的规范化 [MIME 类型](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types) 名称指定为`类型/子类型`，或将扩展后缀形式指定为\"xml\"、\"json\"、\"png\"等：\n\n     request.get('/user')\n       .accept('application/json')\n\n     request.get('/user')\n       .accept('json')\n\n     request.post('/user')\n       .accept('png')\n\n### Facebook 和 Accept JSON\n\n如果您正在调用 Facebook 的 API，请务必在您的请求中发送 `Accept: application/json` 请求头。如果你不这样做，Facebook 会回复 `Content-Type: text/javascript; charset=UTF-8`，SuperAgent 将不会解析，因此 `res.body` 将是未定义的。您可以使用 `req.accept('json')` 或 `req.header('Accept', 'application/json')` 来执行此操作。有关详细信息，请参阅 [issue 1078](https://github.com/ladjs/superagent/issues/1078)。\n\n## 查询字符串(Query strings)\n\n`req.query(obj)` 是一种可用于构建查询字符串的方法。例如在 __POST__ 上增加 `?format=json&dest=/login`：\n\n    request\n      .post('/')\n      .query({ format: 'json' })\n      .query({ dest: '/login' })\n      .send({ post: 'data', here: 'wahoo' })\n      .then(callback);\n\n默认情况下，查询字符串不按任何特定顺序组装。可以使用 `req.sortQuery()` 启用 ASCIIbetically 排序的查询字符串。您还可以使用 `req.sortQuery(myComparisonFn)` 提供自定义排序比较函数。比较函数应该接受 2 个参数并返回一个负/零/正整数。\n\n```js\n // 默认顺序\n request.get('/user')\n   .query('name=Nick')\n   .query('search=Manny')\n   .sortQuery()\n   .then(callback)\n\n // 自定义排序函数\n request.get('/user')\n   .query('name=Nick')\n   .query('search=Manny')\n   .sortQuery((a, b) => a.length - b.length)\n   .then(callback)\n```\n\n## TLS 选项\n\n在 Node.js 中，SuperAgent 支持配置 HTTPS 请求的方法：\n\n- `.ca()`: 将 CA 证书设置为信任\n- `.cert()`: 设置客户端证书链\n- `.key()`: 设置客户端私钥\n- `.pfx()`: 设置客户端 PFX 或 PKCS12 编码的私钥和证书链\n- `.disableTLSCerts()`: 不拒绝过期或无效的 TLS 证书。在内部设置 `rejectUnauthorized=true`。*请注意，此方法允许中间人攻击。*\n\n有关更多信息，请参阅 Node.js [https.request 文档](http://nodejs.cn/api/https.html#httpsrequesturl-options-callback)。\n\n```js\nvar key = fs.readFileSync('key.pem'),\n    cert = fs.readFileSync('cert.pem');\n\nrequest\n  .post('/client-auth')\n  .key(key)\n  .cert(cert)\n  .then(callback);\n```\n\n```js\nvar ca = fs.readFileSync('ca.cert.pem');\n\nrequest\n  .post('https://localhost/private-ca-server')\n  .ca(ca)\n  .then(res => {});\n```\n\n## 解析响应体\n\nSuperAgent将为您解析已知的响应主体数据，目前支持`application/x-www-form-urlencoded`，`application/json`，以及`multipart/form data`。您可以设置自动解析其他响应主体数据：\n\n```js\n//浏览器\nrequest.parse['application/xml'] = function (str) {\n    return {'object': '从str解析的'};\n};\n\n//node\nrequest.parse['application/xml'] = function (res, cb) {\n    //解析响应文本并在此处设置res.body\n\n    cb(null, res);\n};\n\n//接下来，将自动解析 'application/xml' 类型的响应\n```\n\n您可以使用 `.buffer(true).parse(fn)` 方法设置自定义解析器（优先于内置解析器）。如果未启用响应缓冲 (`.buffer(false)`)，则将触发`响应(response)`事件而无需等待正文解析器完成，因此 `response.body` 将不可用。\n\n### JSON / Urlencoded\n\n属性 `res.body` 是解析后的对象，例如，如果请求以 JSON 字符串 '{\"user\":{\"name\":\"tobi\"}}' 响应，则 `res.body.user.name` 将为 \"tobi\" .同样，\"user[name]=tobi\" 的 x-www-form-urlencoded 值将产生相同的结果。仅支持一级嵌套。如果您需要更复杂的数据，请改为发送 JSON。\n\n通过重复的键发送数组。 `.send({color: ['red','blue']})` 会发送 `color=red&color=blue`。如果您希望数组键的名称中包含 `[]`，您必须自己添加它，因为 SuperAgent 不会自动添加它。\n\n### Multipart\n\nNode 客户端通过 [Formidable](https://github.com/felixge/node-formidable) 模块支持 _multipart/form-data_。解析 multipart 响应时，对象 `res.files` 也可供您使用。例如，假设一个请求使用以下 multipart 请求体进行响应：\n\n    --whoop\n    Content-Disposition: attachment; name=\"image\"; filename=\"tobi.png\"\n    Content-Type: image/png\n\n    ... data here ...\n    --whoop\n    Content-Disposition: form-data; name=\"name\"\n    Content-Type: text/plain\n\n    Tobi\n    --whoop--\n\n`res.body.name`的值将为 \"Tobi\"，并且 `res.files.image` 将作为包含磁盘路径、文件名和其他属性的 `File` 对象。\n\n\n### 二进制数据\n\n在浏览器中，您可以使用 `.responseType('blob')` 来请求处理二进制响应体。在 node.js 中运行时不需要此 API。此方法支持的参数值为\n\n- `'blob'` 赋值给 XmlHTTPRequest 的 `responseType` 属性\n- `'arraybuffer'` 赋值给 XmlHTTPRequest 的 responseType 属性\n\n```js\nreq.get('/binary.data')\n  .responseType('blob')\n  .then(res => {\n    // res.body 将是浏览器原生 Blob 类型\n  });\n```\n\n有关更多信息，请参阅 Mozilla 开发人员网络 [xhr.responseType 文档](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/responseType)。\n\n## 响应属性\n\n在 `Response` 对象上设置了许多有用的标志和属性，包括响应文本、解析的响应正文、响应头字段、状态标志等等。\n\n### 响应文本\n\n`res.text` 属性包含未解析的响应正文字符串。此属性始终存在于客户端 API 中，并且仅当默认情况下节点的 mime 类型与 \"text/*\"、\"*/json\" 或 \"x-www-form-urlencoded\" 匹配时。原因是为了节省内存，因为缓冲大型正文（例如 multipart 文件或图像）的文本效率极低。要强制缓冲，请参阅\"[缓冲响应](#缓冲响应)\"部分。\n\n### 响应体\n\n就像 SuperAgent 可以自动序列化请求数据一样，它也可以自动解析响应体。为 Content-Type 定义解析器时，会对其进行解析，默认情况下包括 \"application/json\" 和 \"application/x-www-form-urlencoded\"。然后可以通过 `res.body` 获得解析的对象。\n\n### 响应头字段\n\n`res.header` 包含已解析的响应头字段的对象，字段名称小写，就像 node 做的一样。例如 `res.header['content-length']`。\n\n### 响应内容类型(Content-Type)\n\nContent-Type 响应头是特殊情况，提供 `res.type`，它没有字符集（也可以有）。例如，\"text/html; charset=utf8\" 的 `Content-Type` 将提供 \"text/html\" 作为 `res.type`，然后 `res.charset` 属性将包含 \"utf8\"。\n\n### 响应状态\n\n响应状态标志有助于确定请求是否成功，以及其他有用的信息，使 SuperAgent 成为与 RESTful Web 服务交互的理想选择。这些标志当前定义为：\n\n     var type = status / 100 | 0;\n\n     // status / class\n     res.status = status;\n     res.statusType = type;\n\n     // basics\n     res.info = 1 == type;\n     res.ok = 2 == type;\n     res.clientError = 4 == type;\n     res.serverError = 5 == type;\n     res.error = 4 == type || 5 == type;\n\n     // 语法糖\n     res.accepted = 202 == status;\n     res.noContent = 204 == status || 1223 == status;\n     res.badRequest = 400 == status;\n     res.unauthorized = 401 == status;\n     res.notAcceptable = 406 == status;\n     res.notFound = 404 == status;\n     res.forbidden = 403 == status;\n\n## 中止请求\n\n要中止请求，只需调用 `req.abort()` 方法。\n\n## 超时设定\n\n有时网络和服务器会 \"卡住\" 并且在接受请求后从不响应。设置超时以避免请求永远等待。\n\n  * `req.timeout({deadline:ms})` 或 `req.timeout(ms)`（其中 `ms` 是毫秒数 > 0）设置完成整个请求（包括所有上传、重定向、服务器处理时间）的最后期限。如果在这段时间内没有完全下载响应，则请求将被中止。\n\n  * `req.timeout({response:ms})` 设置等待第一个字节从服务器到达的最长时间，但它不限制整个下载需要多长时间。响应超时应该至少比服务器响应的时间长几秒钟，因为它还包括进行 DNS 查找、TCP/IP 和 TLS 连接的时间，以及上传请求数据的时间。\n\n您应该同时使用 `deadline` 和 `response` 超时。通过这种方式，您可以使用较短的响应超时来快速检测无响应的网络，并使用较长的截止时间来为缓慢但可靠的网络上的下载留出时间。请注意，这两个计时器都限制了允许*上传*附件的时间。如果您要上传文件，请使用长超时。\n\n    request\n      .get('/big-file?network=slow')\n      .timeout({\n        response: 5000,  // 等待 5 秒让服务器开始发送\n        deadline: 60000, // 但允许文件用 1 分钟完成加载。\n      })\n      .then(res => {\n          /* 及时响应 */\n        }, err => {\n          if (err.timeout) { /* 超时! */ } else { /* 其他错误 */ }\n      });\n\n超时错误有个 `.timeout` 属性。\n\n## 验证\n\n在 Node 和浏览器中都可以通过 `.auth()` 方法进行身份验证：\n\n    request\n      .get('http://local')\n      .auth('tobi', 'learnboost')\n      .then(callback);\n\n\n在 _Node_ 客户端中，基本身份验证可以在 URL 中写成 \"user:pass\"：\n\n    request.get('http://tobi:learnboost@local').then(callback);\n\n默认情况下，仅使用`基本(Basic)`身份验证。在浏览器中，您可以添加 `{type:'auto'}` 以启用浏览器中内置的所有方法（Digest、NTLM 等）：\n\n    request.auth('digest', 'secret', {type:'auto'})\n\n`auth` 方法还支持一种`承载类型`，以指定基于令牌的身份验证：\n\n    request.auth('my_token', { type: 'bearer' })\n\n## 跟随重定向\n\n默认情况下将跟随最多 5 个重定向，但是您可以使用 `res.redirects(n)` 方法指定它：\n\n    const response = await request.get('/some.png').redirects(2);\n\n超出限制的重定向被视为错误。使用 `.ok(res => res.status < 400)` 将它们读取为成功响应。\n\n## 全局状态代理程序\n\n### 保存 cookie\n\n在 Node 中 SuperAgent 默认不保存 cookie，但您可以使用 `.agent()` 方法创建保存 cookie 的 SuperAgent 副本。每个副本都有一个单独的 cookie 储存器。\n\n    const agent = request.agent();\n    agent\n      .post('/login')\n      .then(() => {\n        return agent.get('/cookied-page');\n      });\n\n在浏览器中，cookie 由浏览器自动管理，因此 `.agent()` 不会隔离 cookie。\n\n### 多个请求的默认选项\n\n代理程序上调用的常规请求方法将用作该代理发出的所有请求的默认值。\n\n    const agent = request.agent()\n      .use(plugin)\n      .auth(shared);\n\n    await agent.get('/with-plugin-and-auth'); // 带有插件和身份验证\n    await agent.get('/also-with-plugin-and-auth'); // 也带有插件和身份验证\n\n代理可以用来设置默认值的完整方法列表是：`use`、 `on`、 `once`、 `set`、 `query`、 `type`、 `accept`、 `auth`、 `withCredentials`、 `sortQuery`、 `retry`、 `ok`、 `redirects`、 `timeout`、 `buffer`、 `serialize`、 `parse`、 `ca`、 `key`、 `pfx`、 `cert`.\n\n## 管道数据\n\nNode 客户端允许您通过管道将数据传入和传出请求。请注意，使用 `.pipe()` **代替** `.end()/.then()` 方法。\n\n管道文件的内容作为请求的例子：\n\n    const request = require('superagent');\n    const fs = require('fs');\n\n    const stream = fs.createReadStream('path/to/my.json');\n    const req = request.post('/somewhere');\n    req.type('json');\n    stream.pipe(req);\n\n请注意，当您通过管道发送请求时，superagent 使用[分块传输编码](https://baike.baidu.com/item/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81/8359216?fr=aladdin)发送管道数据，并非所有服务器（例如 Python WSGI 服务器）都支持。\n\n或将响应传送到文件：\n\n    const stream = fs.createWriteStream('path/to/my.json');\n    const req = request.get('/some.json');\n    req.pipe(stream);\n\n 不能混合使用管道和回调函数或 promises。请注意，您**不应**尝试通过管道传输 `.end()` 或 `Response` 对象的结果：\n\n    // 别特么这么写：\n    const stream = getAWritableStream();\n    const req = request\n      .get('/some.json')\n      // BAD: 这会将无用信息管道传输到流中并以意想不到的方式失败\n      .end((err, this_does_not_work) => this_does_not_work.pipe(stream))\n    const req = request\n      .get('/some.json')\n      .end()\n      // BAD: 这也不支持，调用 .end 之后调用 .pipe。\n      .pipe(nope_its_too_late);\n\n在 superagent 的[未来版本](https://github.com/ladjs/superagent/issues/1188)中，对 `pipe()` 的不当调用将失败。\n\n## 多部分请求\n\nSuperAgent 也非常适合 _构建_ 它提供方法 `.attach()` 和 `.field()` 的多部分请求。\n\n当您使用 `.field()` 或 `.attach()` 时，您不能使用 `.send()` 并且您*不能*设置 `Content-Type`（将为您设置正确的类型）。\n\n### 附加文件\n\n要发送文件，请使用 `.attach(name, [file], [options])`。您可以通过多次调用 `.attach` 来附加多个文件。参数是：\n\n * `name` — form 表单中的字段名。\n * `file` — 带有文件路径的字符串或 `Blob/Buffer` 对象。\n * `options` — （可选）自定义文件名的字符串或 `{filename: string}` 对象。在 Node 中也支持 `{contentType: 'mime/type'}`。在浏览器中创建一个具有适当类型的 `Blob`。\n \n<br>\n\n    request\n      .post('/upload')\n      .attach('image1', 'path/to/felix.jpeg')\n      .attach('image2', imageBuffer, 'luna.jpeg')\n      .field('caption', 'My cats')\n      .then(callback);\n\n### 字段值\n\n与 HTML 中的表单字段非常相似，您可以使用 `.field(name, value)` 和 `.field({name: value})` 设置字段值。假设您想上传一些带有您的姓名和电子邮件的图片，您的请求可能如下所示：\n\n     request\n       .post('/upload')\n       .field('user[name]', 'Tobi')\n       .field('user[email]', 'tobi@learnboost.com')\n       .field('friends[]', ['loki', 'jane'])\n       .attach('image', 'path/to/tobi.png')\n       .then(callback);\n\n## 压缩\n\nnode 客户端支持压缩过的响应，最重要的是，您无需执行任何操作！它就能用。\n\n## 缓冲响应\n\n要强制将响应主体缓冲为 `res.text`，您可以调用 `req.buffer()`。要取消对文本响应（例如 \"text/plain\"、\"text/html\" 等）的默认缓冲，您可以调用 `req.buffer(false)`。 \n\n当缓冲提供 `res.buffered` 标志时，您可以使用它在同一个回调中处理缓冲和非缓冲响应。\n\n## CORS\n\n出于安全原因，浏览器将阻止跨域请求，除非服务器选择使用 CORS 标头。浏览器还会发出额外的 __OPTIONS__ 请求来检查服务器允许哪些 HTTP 标头和方法。[阅读有关 CORS 的更多信息](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS)。\n\n`.withCredentials()` 方法支持从源发送 cookie，但仅当 Access-Control-Allow-Origin _不是_ 通配符 (\"*\") 且 `Access-Control-Allow-Credentials` 为 \"true\" 时。\n\n    request\n      .get('https://api.example.com:4001/')\n      .withCredentials()\n      .then(res => {\n        assert.equal(200, res.status);\n        assert.equal('tobi', res.text);\n      })\n\n## 错误处理\n\n您的回调函数将始终传递两个参数：错误和响应。如果没有发生错误，第一个参数将为`null`：\n\n    request\n     .post('/upload')\n     .attach('image', 'path/to/tobi.png')\n     .then(res => {\n\n     });\n\n还会触发\"错误\"事件，您可以监听：\n\n    request\n      .post('/upload')\n      .attach('image', 'path/to/tobi.png')\n      .on('error', handle)\n      .then(res => {\n\n      });\n\n请注意，**默认情况下，superagent 会考虑 4xx 和 5xx 响应（以及未处理的 3xx 响应）视为错误**。例如，如果您收到 `304 Not modified`、`403 Forbidden` 或 `500 Internal server` 错误响应，则此状态信息将通过 `err.status` 提供。来自此类响应的错误还包含一个 `err.response` 字段，其中包含\"[响应属性](#响应属性)\"中提到的所有属性。该库以这种方式运行以处理需要成功响应并将 HTTP 错误状态代码视为错误的常见情况，同时仍允许围绕特定错误条件进行自定义逻辑。\n\n网络故障、超时和其他不产生响应的错误将不包含 `err.status` 或 `err.response` 字段。\n\n如果您希望处理 404 或其他 HTTP 错误响应，您可以查询 `err.status` 属性。当发生 HTTP 错误（4xx 或 5xx 响应）时， `res.error` 属性是一个 `Error` 对象，这允许您执行以下检查：\n\n    if (err && err.status === 404) {\n      alert('oh no ' + res.body.message);\n    }\n    else if (err) {\n      // 所有其他需要处理的错误类型\n    }\n\n或者，您可以使用 `.ok(callback)` 方法来确定响应是否为错误。 `ok` 函数的回调函数获得响应，如果响应应该被解释为成功，则返回 true。\n\n    request.get('/404')\n      .ok(res => res.status < 500)\n      .then(response => {\n        // 将 404 页面作为成功响应\n      })\n\n## 进度跟踪\n\nSuperAgent 在上传和下载大文件时触发 `progress` 事件。\n\n    request.post(url)\n      .attach('field_name', file)\n      .on('progress', event => {\n        /* event的值：\n        {\n          direction: \"upload\" or \"download\"\n          percent: 0 to 100 // 如果文件大小未知，可能会没有\n          total: // 总文件大小，可能没有\n          loaded: // 到目前为止下载或上传的字节数\n        } */\n      })\n      .then()\n\n\n## 在本地主机上测试\n\n### 强制连接特定 IP 地址\n\n在 Node.js 中，可以忽略 DNS 解析并使用 `.connect()` 方法将所有请求定向到特定 IP 地址。例如，此请求将转到 localhost 而不是 `example.com`：\n\n    const res = await request.get(\"http://example.com\").connect(\"127.0.0.1\");\n\n因为请求可能被重定向，所以可以指定多个主机名和多个 IP，以及一个特殊的 `*` 作为后备（注意：不支持其他通配符）。请求将保留其 `Host` 请求头的原始值。\n\n    const res = await request.get(\"http://redir.example.com:555\")\n      .connect({\n        \"redir.example.com\": \"127.0.0.1\", // redir.example.com:555 将使用 127.0.0.1:555\n        \"www.example.com\": false, // 不覆盖这个；正常使用 DNS\n        \"mapped.example.com\": { host: \"127.0.0.1\", port: 8080}, // mapped.example.com:* 将使用 127.0.0.1:8080\n        \"*\": \"proxy.example.com\", // 所有其他请求都将发送到该主机\n      });\n\n### 忽略本地主机上损坏/不安全的 HTTPS\n\n在 Node.js 中，当 HTTPS 配置错误且不安全（例如，使用自签名证书而*不指定*自己的 `.ca()`）时，仍然可以通过调用 `.trustLocalhost()` 来允许对 `localhost` 的请求：\n\n    const res = await request.get(\"https://localhost\").trustLocalhost()\n\n与 `.connect(\"127.0.0.1\")` 一起，这可用于强制将对任何域的 HTTPS 请求重新路由到 `localhost`。\n\n忽略本地主机上损坏的 HTTPS 通常是安全的，因为环回接口不会暴露给不受信任的网络。信任 `localhost` 可能会成为未来的默认设置。使用 `.trustLocalhost(false)` 强制检查 `127.0.0.1` 的可靠性。\n\n当向任何其他 IP 发出请求时，我们故意不支持禁用 HTTPS 安全性，因为这些选项最终被滥用为 HTTPS 问题的快速\"修复\"。您可以从 [Let's Encrypt](https://certbot.eff.org) 获得免费的 HTTPS 证书或设置您自己的 CA (`.ca(ca_public_pem)`) 以使您的自签名证书受信任。\n\n## Promise 和生成器函数支持\n\nSuperAgent 的请求是一个 \"thenable\" 对象(带有then方法的对象)，它与 JavaScript Promise 和 `async/await` 语法兼容。\n\n    const res = await request.get(url);\n\n如果你使用 Promise，**不要**调用 `.end()` 或 `.pipe()`。任何使用 `.then()` 或 `await` 都会禁用所有其他使用请求的方式。 像 [co](https://github.com/tj/co) 这样的库或像 [koa](https://github.com/koajs/koa) 这样的 web 框架可以在任何 SuperAgent 方法上 `yield`：\n\n    const req = request\n      .get('http://local')\n      .auth('tobi', 'learnboost');\n    const res = yield req;\n\n请注意，SuperAgent 期望全局 `Promise` 对象存在。您需要一个 polyfill 才能在 Internet Explorer 或 Node.js 0.10 中使用 Promise。\n\n## 浏览器和 node 版本\n\nSuperAgent 有两种实现：一种用于 Web 浏览器（使用 XHR），另一种用于 Node.JS（使用核心 http 模块）。默认情况下，Browserify 和 WebPack 将选择浏览器版本。 \n\n如果要使用 WebPack 为 Node.JS 编译代码，您*必须*在其配置中指定[node target](https://webpack.github.io/docs/configuration.html#target)。\n\n### 在 electron 中使用浏览器版本\n\n[Electron](https://electron.atom.io/) 开发人员报告说，如果您希望使用浏览器版本的 SuperAgent 而不是 Node 版本，您可以 `require('superagent/superagent')`。这样您的请求将显示在 Chrome 开发者工具的\"网络(Network)\"选项卡中。请注意，自动化测试套件未涵盖此环境，也未得到官方支持。\n\n## 使用代理发送请求\n\n可以使用另一个作者的 [superagent-proxy](https://www.npmjs.com/package/superagent-proxy) 模块\n\n## 翻译说明\n\n文档全部内容都是根据原英文文档翻译的，译者也没水平，所以如果有错误还请指出"
  },
  {
    "path": "examples/simple-get.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst request = require('..');\n\nconst url =\n  'https://gist.githubusercontent.com/reinaldo13/cdbb4d663ba23410a77b/raw/0345267767d50790051951ddc460e2699649de2b/it-works.txt';\n\nrequest.get(url, (error, res) => {\n  if (error) throw error;\n  console.log(res.text);\n});\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css\">\n    <link rel=\"stylesheet\" href=\"docs/style.css\">\n  </head>\n  <body>\n    <ul id=\"menu\"></ul>\n    <div id=\"content\">\n<h1 id=\"superagent\">SuperAgent</h1>\n<p>SuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!</p>\n<pre><code class=\"language-javascript\">     request\n       .post(&#39;/api/pet&#39;)\n       .send({ name: &#39;Manny&#39;, species: &#39;cat&#39; })\n       .set(&#39;X-API-Key&#39;, &#39;foobar&#39;)\n       .set(&#39;Accept&#39;, &#39;application/json&#39;)\n       .then(res =&gt; {\n          alert(&#39;yay got &#39; + JSON.stringify(res.body));\n       });\n</code></pre>\n<h2 id=\"test-documentation\">Test documentation</h2>\n<p><a href=\"docs/zh_CN/index.html\"><strong>中文文档</strong></a></p>\n<p>The following <a href=\"docs/test.html\">test documentation</a> was generated with <a href=\"https://mochajs.org/\">Mocha&#39;s</a> &quot;doc&quot; reporter, and directly reflects the test suite. This provides an additional source of documentation.</p>\n<h2 id=\"request-basics\">Request basics</h2>\n<p>A request can be initiated by invoking the appropriate method on the <code>request</code> object, then calling <code>.then()</code> (or <code>.end()</code> <a href=\"#promise-and-generator-support\">or <code>await</code></a>) to send the request. For example a simple <strong>GET</strong> request:</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .then(res =&gt; {\n          // res.body, res.headers, res.status\n       })\n       .catch(err =&gt; {\n          // err.message, err.response\n       });\n</code></pre>\n<p>HTTP method may also be passed as a string:</p>\n<pre><code class=\"language-javascript\">    request(&#39;GET&#39;, &#39;/search&#39;).then(success, failure);\n</code></pre>\n<p>Old-style callbacks are also supported, but not recommended. <em>Instead of</em> <code>.then()</code> you can call <code>.end()</code>:</p>\n<pre><code class=\"language-javascript\">    request(&#39;GET&#39;, &#39;/search&#39;).end(function(err, res){\n      if (res.ok) {}\n    });\n</code></pre>\n<p>Absolute URLs can be used. In web browsers absolute URLs work only if the server implements <a href=\"#cors\">CORS</a>.</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;https://example.com/search&#39;)\n       .then(res =&gt; {\n\n       });\n</code></pre>\n<p>The <strong>Node</strong> client supports making requests to <a href=\"https://en.wikipedia.org/wiki/Unix_domain_socket\">Unix Domain Sockets</a>:</p>\n<pre><code class=\"language-javascript\">    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH\n    //          Use `%2F` as `/` in SOCKET_PATH\n    try {\n      const res = await request\n        .get(&#39;http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search&#39;);\n      // res.body, res.headers, res.status\n    } catch(err) {\n      // err.message, err.response\n    }\n</code></pre>\n<p><strong>DELETE</strong>, <strong>HEAD</strong>, <strong>PATCH</strong>, <strong>POST</strong>, and <strong>PUT</strong> requests can also be used, simply change the method name:</p>\n<pre><code class=\"language-javascript\">    request\n      .head(&#39;/favicon.ico&#39;)\n      .then(res =&gt; {\n\n      });\n</code></pre>\n<p><strong>DELETE</strong> can be also called as <code>.del()</code> for compatibility with old IE where <code>delete</code> is a reserved word.</p>\n<p>The HTTP method defaults to <strong>GET</strong>, so if you wish, the following is valid:</p>\n<pre><code class=\"language-javascript\">     request(&#39;/search&#39;, (err, res) =&gt; {\n\n     });\n</code></pre>\n<h2 id=\"using-http/2\">Using HTTP/2</h2>\n<p>To make a request using HTTP/2 protocol only (with no HTTP/1.x fallback), use the <code>.http2()</code> method.</p>\n<pre><code class=\"language-javascript\">    const request = require(&#39;superagent&#39;);\n    const res = await request\n      .get(&#39;https://example.com/h2&#39;)\n      .http2();\n</code></pre>\n<h2 id=\"setting-header-fields\">Setting header fields</h2>\n<p>Setting header fields is simple, invoke <code>.set()</code> with a field name and value:</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .set(&#39;API-Key&#39;, &#39;foobar&#39;)\n       .set(&#39;Accept&#39;, &#39;application/json&#39;)\n       .then(callback);\n</code></pre>\n<p>You may also pass an object to set several fields in a single call:</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .set({ &#39;API-Key&#39;: &#39;foobar&#39;, Accept: &#39;application/json&#39; })\n       .then(callback);\n</code></pre>\n<h2 id=\"get-requests\"><code>GET</code> requests</h2>\n<p>The <code>.query()</code> method accepts objects, which when used with the <strong>GET</strong> method will form a query-string. The following will produce the path <code>/search?query=Manny&amp;range=1..5&amp;order=desc</code>.</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;/search&#39;)\n       .query({ query: &#39;Manny&#39; })\n       .query({ range: &#39;1..5&#39; })\n       .query({ order: &#39;desc&#39; })\n       .then(res =&gt; {\n\n       });\n</code></pre>\n<p>Or as a single object:</p>\n<pre><code class=\"language-javascript\">    request\n      .get(&#39;/search&#39;)\n      .query({ query: &#39;Manny&#39;, range: &#39;1..5&#39;, order: &#39;desc&#39; })\n      .then(res =&gt; {\n\n      });\n</code></pre>\n<p>The <code>.query()</code> method accepts strings as well:</p>\n<pre><code class=\"language-javascript\">      request\n        .get(&#39;/querystring&#39;)\n        .query(&#39;search=Manny&amp;range=1..5&#39;)\n        .then(res =&gt; {\n\n        });\n</code></pre>\n<p>Or joined:</p>\n<pre><code class=\"language-javascript\">      request\n        .get(&#39;/querystring&#39;)\n        .query(&#39;search=Manny&#39;)\n        .query(&#39;range=1..5&#39;)\n        .then(res =&gt; {\n\n        });\n</code></pre>\n<h2 id=\"head-requests\"><code>HEAD</code> requests</h2>\n<p>You can also use the <code>.query()</code> method for HEAD requests. The following will produce the path <code>/users?email=joe@smith.com</code>.</p>\n<pre><code class=\"language-javascript\">      request\n        .head(&#39;/users&#39;)\n        .query({ email: &#39;joe@smith.com&#39; })\n        .then(res =&gt; {\n\n        });\n</code></pre>\n<h2 id=\"post--put-requests\"><code>POST</code> / <code>PUT</code> requests</h2>\n<p>A typical JSON <strong>POST</strong> request might look a little like the following, where we set the Content-Type header field appropriately, and &quot;write&quot; some data, in this case just a JSON string.</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n        .send(&#39;{&quot;name&quot;:&quot;tj&quot;,&quot;pet&quot;:&quot;tobi&quot;}&#39;)\n        .then(callback)\n        .catch(errorCallback)\n</code></pre>\n<p>Since JSON is undoubtedly the most common, it&#39;s the <em>default</em>! The following example is equivalent to the previous.</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send({ name: &#39;tj&#39;, pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n<p>Or using multiple <code>.send()</code> calls:</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send({ name: &#39;tj&#39; })\n        .send({ pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n<p>By default sending strings will set the <code>Content-Type</code> to <code>application/x-www-form-urlencoded</code>,\n  multiple calls will be concatenated with <code>&amp;</code>, here resulting in <code>name=tj&amp;pet=tobi</code>:</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send(&#39;name=tj&#39;)\n        .send(&#39;pet=tobi&#39;)\n        .then(callback, errorCallback);\n</code></pre>\n<p>SuperAgent formats are extensible, however by default &quot;json&quot; and &quot;form&quot; are supported. To send the data as <code>application/x-www-form-urlencoded</code> simply invoke <code>.type()</code> with &quot;form&quot;, where the default is &quot;json&quot;. This request will <strong>POST</strong> the body &quot;name=tj&amp;pet=tobi&quot;.</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .type(&#39;form&#39;)\n        .send({ name: &#39;tj&#39; })\n        .send({ pet: &#39;tobi&#39; })\n        .then(callback, errorCallback)\n</code></pre>\n<p>Sending a <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData\"><code>FormData</code></a> object is also supported. The following example will <strong>POST</strong> the content of the HTML form identified by id=&quot;myForm&quot;:</p>\n<pre><code class=\"language-javascript\">      request.post(&#39;/user&#39;)\n        .send(new FormData(document.getElementById(&#39;myForm&#39;)))\n        .then(callback, errorCallback)\n</code></pre>\n<h2 id=\"setting-the-content-type\">Setting the <code>Content-Type</code></h2>\n<p>The obvious solution is to use the <code>.set()</code> method:</p>\n<pre><code class=\"language-javascript\">     request.post(&#39;/user&#39;)\n       .set(&#39;Content-Type&#39;, &#39;application/json&#39;)\n</code></pre>\n<p>As a short-hand the <code>.type()</code> method is also available, accepting\nthe canonicalized MIME type name complete with type/subtype, or\nsimply the extension name such as &quot;xml&quot;, &quot;json&quot;, &quot;png&quot;, etc:</p>\n<pre><code class=\"language-javascript\">     request.post(&#39;/user&#39;)\n       .type(&#39;application/json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .type(&#39;json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .type(&#39;png&#39;)\n</code></pre>\n<h2 id=\"serializing-request-body\">Serializing request body</h2>\n<p>SuperAgent will automatically serialize JSON and forms.\nYou can setup automatic serialization for other types as well:</p>\n<pre><code class=\"language-js\">request.serialize[&#39;application/xml&#39;] = function (obj) {\n    return &#39;string generated from obj&#39;;\n};\n\n// going forward, all requests with a Content-type of\n// &#39;application/xml&#39; will be automatically serialized\n</code></pre>\n<p>If you want to send the payload in a custom format, you can replace\nthe built-in serialization with the <code>.serialize()</code> method on a per-request basis:</p>\n<pre><code class=\"language-js\">request\n    .post(&#39;/user&#39;)\n    .send({foo: &#39;bar&#39;})\n    .serialize(obj =&gt; {\n        return &#39;string generated from obj&#39;;\n    });\n</code></pre>\n<h2 id=\"retrying-requests\">Retrying requests</h2>\n<p>When given the <code>.retry()</code> method, SuperAgent will automatically retry requests, if they fail in a way that is transient or could be due to a flaky Internet connection.</p>\n<p>This method has two optional arguments: number of retries (default 1) and a callback. It calls <code>callback(err, res)</code> before each retry. The callback may return <code>true</code>/<code>false</code> to control whether the request should be retried (but the maximum number of retries is always applied).</p>\n<pre><code class=\"language-javascript\">     request\n       .get(&#39;https://example.com/search&#39;)\n       .retry(2) // or:\n       .retry(2, callback)\n       .then(finished);\n       .catch(failed);\n</code></pre>\n<p>Use <code>.retry()</code> only with requests that are <em>idempotent</em> (i.e. multiple requests reaching the server won&#39;t cause undesirable side effects like duplicate purchases).</p>\n<p>All request methods are tried by default (which means if you do not want POST requests to be retried, you will need to pass a custom retry callback).</p>\n<p>By default the following status codes are retried:</p>\n<ul>\n<li><code>408</code></li>\n<li><code>413</code></li>\n<li><code>429</code></li>\n<li><code>500</code></li>\n<li><code>502</code></li>\n<li><code>503</code></li>\n<li><code>504</code></li>\n<li><code>521</code></li>\n<li><code>522</code></li>\n<li><code>524</code></li>\n</ul>\n<p>By default the following error codes are retried:</p>\n<ul>\n<li><code>&#39;ETIMEDOUT&#39;</code></li>\n<li><code>&#39;ECONNRESET&#39;</code></li>\n<li><code>&#39;EADDRINUSE&#39;</code></li>\n<li><code>&#39;ECONNREFUSED&#39;</code></li>\n<li><code>&#39;EPIPE&#39;</code></li>\n<li><code>&#39;ENOTFOUND&#39;</code></li>\n<li><code>&#39;ENETUNREACH&#39;</code></li>\n<li><code>&#39;EAI_AGAIN&#39;</code></li>\n</ul>\n<h2 id=\"setting-accept\">Setting Accept</h2>\n<p>In a similar fashion to the <code>.type()</code> method it is also possible to set the <code>Accept</code> header via the short hand method <code>.accept()</code>. Which references <code>request.types</code> as well allowing you to specify either the full canonicalized MIME type name as <code>type/subtype</code>, or the extension suffix form as &quot;xml&quot;, &quot;json&quot;, &quot;png&quot;, etc. for convenience:</p>\n<pre><code class=\"language-javascript\">     request.get(&#39;/user&#39;)\n       .accept(&#39;application/json&#39;)\n\n     request.get(&#39;/user&#39;)\n       .accept(&#39;json&#39;)\n\n     request.post(&#39;/user&#39;)\n       .accept(&#39;png&#39;)\n</code></pre>\n<h3 id=\"facebook-and-accept-json\">Facebook and Accept JSON</h3>\n<p>If you are calling Facebook&#39;s API, be sure to send an <code>Accept: application/json</code> header in your request. If you don&#39;t do this, Facebook will respond with <code>Content-Type: text/javascript; charset=UTF-8</code>, which SuperAgent will not parse and thus <code>res.body</code> will be undefined. You can do this with either <code>req.accept(&#39;json&#39;)</code> or <code>req.set(&#39;Accept&#39;, &#39;application/json&#39;)</code>. See <a href=\"https://github.com/ladjs/superagent/issues/1078\">issue 1078</a> for details.</p>\n<h2 id=\"query-strings\">Query strings</h2>\n<p>  <code>req.query(obj)</code> is a method which may be used to build up a query-string. For example populating <code>?format=json&amp;dest=/login</code> on a <strong>POST</strong>:</p>\n<pre><code class=\"language-javascript\">    request\n      .post(&#39;/&#39;)\n      .query({ format: &#39;json&#39; })\n      .query({ dest: &#39;/login&#39; })\n      .send({ post: &#39;data&#39;, here: &#39;wahoo&#39; })\n      .then(callback);\n</code></pre>\n<p>By default the query string is not assembled in any particular order. An asciibetically-sorted query string can be enabled with <code>req.sortQuery()</code>. You may also provide a custom sorting comparison function with <code>req.sortQuery(myComparisonFn)</code>. The comparison function should take 2 arguments and return a negative/zero/positive integer.</p>\n<pre><code class=\"language-js\"> // default order\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery()\n   .then(callback)\n\n // customized sort function\n request.get(&#39;/user&#39;)\n   .query(&#39;name=Nick&#39;)\n   .query(&#39;search=Manny&#39;)\n   .sortQuery((a, b) =&gt; a.length - b.length)\n   .then(callback)\n</code></pre>\n<h2 id=\"tls-options\">TLS options</h2>\n<p>In Node.js SuperAgent supports methods to configure HTTPS requests:</p>\n<ul>\n<li><code>.ca()</code>: Set the CA certificate(s) to trust</li>\n<li><code>.cert()</code>: Set the client certificate chain(s)</li>\n<li><code>.key()</code>: Set the client private key(s)</li>\n<li><code>.pfx()</code>: Set the client PFX or PKCS12 encoded private key and certificate chain</li>\n<li><code>.disableTLSCerts()</code>: Does not reject expired or invalid TLS certs. Sets internally <code>rejectUnauthorized=true</code>. <em>Be warned, this method allows MITM attacks.</em></li>\n</ul>\n<p>For more information, see Node.js <a href=\"https://nodejs.org/api/https.html#https_https_request_options_callback\">https.request docs</a>.</p>\n<pre><code class=\"language-js\">var key = fs.readFileSync(&#39;key.pem&#39;),\n    cert = fs.readFileSync(&#39;cert.pem&#39;);\n\nrequest\n  .post(&#39;/client-auth&#39;)\n  .key(key)\n  .cert(cert)\n  .then(callback);\n</code></pre>\n<pre><code class=\"language-js\">var ca = fs.readFileSync(&#39;ca.cert.pem&#39;);\n\nrequest\n  .post(&#39;https://localhost/private-ca-server&#39;)\n  .ca(ca)\n  .then(res =&gt; {});\n</code></pre>\n<h2 id=\"parsing-response-bodies\">Parsing response bodies</h2>\n<p>SuperAgent will parse known response-body data for you,\ncurrently supporting <code>application/x-www-form-urlencoded</code>,\n<code>application/json</code>, and <code>multipart/form-data</code>. You can setup\nautomatic parsing for other response-body data as well:</p>\n<pre><code class=\"language-js\">//browser\nrequest.parse[&#39;application/xml&#39;] = function (str) {\n    return {&#39;object&#39;: &#39;parsed from str&#39;};\n};\n\n//node\nrequest.parse[&#39;application/xml&#39;] = function (res, cb) {\n    //parse response text and set res.body here\n\n    cb(null, res);\n};\n\n//going forward, responses of type &#39;application/xml&#39;\n//will be parsed automatically\n</code></pre>\n<p>You can set a custom parser (that takes precedence over built-in parsers) with the <code>.buffer(true).parse(fn)</code> method. If response buffering is not enabled (<code>.buffer(false)</code>) then the <code>response</code> event will be emitted without waiting for the body parser to finish, so <code>response.body</code> won&#39;t be available.</p>\n<h3 id=\"json--urlencoded\">JSON / Urlencoded</h3>\n<p>The property <code>res.body</code> is the parsed object, for example if a request responded with the JSON string &#39;{&quot;user&quot;:{&quot;name&quot;:&quot;tobi&quot;}}&#39;, <code>res.body.user.name</code> would be &quot;tobi&quot;. Likewise the x-www-form-urlencoded value of &quot;user[name]=tobi&quot; would yield the same result. Only one level of nesting is supported. If you need more complex data, send JSON instead.</p>\n<p>Arrays are sent by repeating the key. <code>.send({color: [&#39;red&#39;,&#39;blue&#39;]})</code> sends <code>color=red&amp;color=blue</code>. If you want the array keys to contain <code>[]</code> in their name, you must add it yourself, as SuperAgent doesn&#39;t add it automatically.</p>\n<h3 id=\"multipart\">Multipart</h3>\n<p>The Node client supports <em>multipart/form-data</em> via the <a href=\"https://github.com/felixge/node-formidable\">Formidable</a> module. When parsing multipart responses, the object <code>res.files</code> is also available to you. Suppose for example a request responds with the following multipart body:</p>\n<pre><code>--whoop\nContent-Disposition: attachment; name=&quot;image&quot;; filename=&quot;tobi.png&quot;\nContent-Type: image/png\n\n... data here ...\n--whoop\nContent-Disposition: form-data; name=&quot;name&quot;\nContent-Type: text/plain\n\nTobi\n--whoop--\n</code></pre>\n<p>You would have the values <code>res.body.name</code> provided as &quot;Tobi&quot;, and <code>res.files.image</code> as a <code>File</code> object containing the path on disk, filename, and other properties.</p>\n<h3 id=\"binary\">Binary</h3>\n<p>In browsers, you may use <code>.responseType(&#39;blob&#39;)</code> to request handling of binary response bodies. This API is unnecessary when running in node.js. The supported argument values for this method are</p>\n<ul>\n<li><code>&#39;blob&#39;</code> passed through to the XmlHTTPRequest <code>responseType</code> property</li>\n<li><code>&#39;arraybuffer&#39;</code> passed through to the XmlHTTPRequest <code>responseType</code> property</li>\n</ul>\n<pre><code class=\"language-js\">req.get(&#39;/binary.data&#39;)\n  .responseType(&#39;blob&#39;)\n  .then(res =&gt; {\n    // res.body will be a browser native Blob type here\n  });\n</code></pre>\n<p>For more information, see the Mozilla Developer Network <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType\">xhr.responseType docs</a>.</p>\n<h2 id=\"response-properties\">Response properties</h2>\n<p>Many helpful flags and properties are set on the <code>Response</code> object, ranging from the response text, parsed response body, header fields, status flags and more.</p>\n<h3 id=\"response-text\">Response text</h3>\n<p>The <code>res.text</code> property contains the unparsed response body string. This property is always present for the client API, and only when the mime type matches &quot;text/<em>&quot;, &quot;</em>/json&quot;, or &quot;x-www-form-urlencoded&quot; by default for node. The reasoning is to conserve memory, as buffering text of large bodies such as multipart files or images is extremely inefficient. To force buffering see the &quot;Buffering responses&quot; section.</p>\n<h3 id=\"response-body\">Response body</h3>\n<p>Much like SuperAgent can auto-serialize request data, it can also automatically parse it. When a parser is defined for the Content-Type, it is parsed, which by default includes &quot;application/json&quot; and &quot;application/x-www-form-urlencoded&quot;. The parsed object is then available via <code>res.body</code>.</p>\n<h3 id=\"response-header-fields\">Response header fields</h3>\n<p>The <code>res.header</code> contains an object of parsed header fields, lowercasing field names much like node does. For example <code>res.header[&#39;content-length&#39;]</code>.</p>\n<h3 id=\"response-content-type\">Response Content-Type</h3>\n<p>The Content-Type response header is special-cased, providing <code>res.type</code>, which is void of the charset (if any). For example the Content-Type of &quot;text/html; charset=utf8&quot; will provide &quot;text/html&quot; as <code>res.type</code>, and the <code>res.charset</code> property would then contain &quot;utf8&quot;.</p>\n<h3 id=\"response-status\">Response status</h3>\n<p>The response status flags help determine if the request was a success, among other useful information, making SuperAgent ideal for interacting with RESTful web services. These flags are currently defined as:</p>\n<pre><code class=\"language-javascript\">     var type = status / 100 | 0;\n\n     // status / class\n     res.status = status;\n     res.statusType = type;\n\n     // basics\n     res.info = 1 == type;\n     res.ok = 2 == type;\n     res.clientError = 4 == type;\n     res.serverError = 5 == type;\n     res.error = 4 == type || 5 == type;\n\n     // sugar\n     res.accepted = 202 == status;\n     res.noContent = 204 == status || 1223 == status;\n     res.badRequest = 400 == status;\n     res.unauthorized = 401 == status;\n     res.notAcceptable = 406 == status;\n     res.notFound = 404 == status;\n     res.forbidden = 403 == status;\n</code></pre>\n<h2 id=\"aborting-requests\">Aborting requests</h2>\n<p>To abort requests simply invoke the <code>req.abort()</code> method.</p>\n<h2 id=\"timeouts\">Timeouts</h2>\n<p>Sometimes networks and servers get &quot;stuck&quot; and never respond after accepting a request. Set timeouts to avoid requests waiting forever.</p>\n<ul>\n<li><p><code>req.timeout({deadline:ms})</code> or <code>req.timeout(ms)</code> (where <code>ms</code> is a number of milliseconds &gt; 0) sets a deadline for the entire request (including all uploads, redirects, server processing time) to complete. If the response isn&#39;t fully downloaded within that time, the request will be aborted.</p>\n</li>\n<li><p><code>req.timeout({response:ms})</code> sets maximum time to wait for the first byte to arrive from the server, but it does not limit how long the entire download can take. Response timeout should be at least few seconds longer than just the time it takes the server to respond, because it also includes time to make DNS lookup, TCP/IP and TLS connections, and time to upload request data.</p>\n</li>\n</ul>\n<p>You should use both <code>deadline</code> and <code>response</code> timeouts. This way you can use a short response timeout to detect unresponsive networks quickly, and a long deadline to give time for downloads on slow, but reliable, networks. Note that both of these timers limit how long <em>uploads</em> of attached files are allowed to take. Use long timeouts if you&#39;re uploading files.</p>\n<pre><code class=\"language-javascript\">    request\n      .get(&#39;/big-file?network=slow&#39;)\n      .timeout({\n        response: 5000,  // Wait 5 seconds for the server to start sending,\n        deadline: 60000, // but allow 1 minute for the file to finish loading.\n      })\n      .then(res =&gt; {\n          /* responded in time */\n        }, err =&gt; {\n          if (err.timeout) { /* timed out! */ } else { /* other error */ }\n      });\n</code></pre>\n<p>Timeout errors have a <code>.timeout</code> property.</p>\n<h2 id=\"authentication\">Authentication</h2>\n<p>In both Node and browsers auth available via the <code>.auth()</code> method:</p>\n<pre><code class=\"language-javascript\">    request\n      .get(&#39;http://local&#39;)\n      .auth(&#39;tobi&#39;, &#39;learnboost&#39;)\n      .then(callback);\n</code></pre>\n<p>In the <em>Node</em> client Basic auth can be in the URL as &quot;user:pass&quot;:</p>\n<pre><code class=\"language-javascript\">    request.get(&#39;http://tobi:learnboost@local&#39;).then(callback);\n</code></pre>\n<p>By default only <code>Basic</code> auth is used. In browser you can add <code>{type:&#39;auto&#39;}</code> to enable all methods built-in in the browser (Digest, NTLM, etc.):</p>\n<pre><code class=\"language-javascript\">    request.auth(&#39;digest&#39;, &#39;secret&#39;, {type:&#39;auto&#39;})\n</code></pre>\n<p>The <code>auth</code> method also supports a <code>type</code> of <code>bearer</code>, to specify token-based authentication:</p>\n<pre><code class=\"language-javascript\">    request.auth(&#39;my_token&#39;, { type: &#39;bearer&#39; })\n</code></pre>\n<h2 id=\"following-redirects\">Following redirects</h2>\n<p>By default up to 5 redirects will be followed, however you may specify this with the <code>res.redirects(n)</code> method:</p>\n<pre><code class=\"language-javascript\">    const response = await request.get(&#39;/some.png&#39;).redirects(2);\n</code></pre>\n<p>Redirects exceeding the limit are treated as errors. Use <code>.ok(res =&gt; res.status &lt; 400)</code> to read them as successful responses.</p>\n<h2 id=\"agents-for-global-state\">Agents for global state</h2>\n<h3 id=\"saving-cookies\">Saving cookies</h3>\n<p>In Node SuperAgent does not save cookies by default, but you can use the <code>.agent()</code> method to create a copy of SuperAgent that saves cookies. Each copy has a separate cookie jar.</p>\n<pre><code class=\"language-javascript\">    const agent = request.agent();\n    agent\n      .post(&#39;/login&#39;)\n      .then(() =&gt; {\n        return agent.get(&#39;/cookied-page&#39;);\n      });\n</code></pre>\n<p>In browsers cookies are managed automatically by the browser, so the <code>.agent()</code> does not isolate cookies.</p>\n<h3 id=\"default-options-for-multiple-requests\">Default options for multiple requests</h3>\n<p>Regular request methods called on the agent will be used as defaults for all requests made by that agent.</p>\n<pre><code class=\"language-javascript\">    const agent = request.agent()\n      .use(plugin)\n      .auth(shared);\n\n    await agent.get(&#39;/with-plugin-and-auth&#39;);\n    await agent.get(&#39;/also-with-plugin-and-auth&#39;);\n</code></pre>\n<p>The complete list of methods that the agent can use to set defaults is: <code>use</code>, <code>on</code>, <code>once</code>, <code>set</code>, <code>query</code>, <code>type</code>, <code>accept</code>, <code>auth</code>, <code>withCredentials</code>, <code>sortQuery</code>, <code>retry</code>, <code>ok</code>, <code>redirects</code>, <code>timeout</code>, <code>buffer</code>, <code>serialize</code>, <code>parse</code>, <code>ca</code>, <code>key</code>, <code>pfx</code>, <code>cert</code>.</p>\n<h2 id=\"piping-data\">Piping data</h2>\n<p>The Node client allows you to pipe data to and from the request. Please note that <code>.pipe()</code> is used <strong>instead of</strong> <code>.end()</code>/<code>.then()</code> methods.</p>\n<p>For example piping a file&#39;s contents as the request:</p>\n<pre><code class=\"language-javascript\">    const request = require(&#39;superagent&#39;);\n    const fs = require(&#39;fs&#39;);\n\n    const stream = fs.createReadStream(&#39;path/to/my.json&#39;);\n    const req = request.post(&#39;/somewhere&#39;);\n    req.type(&#39;json&#39;);\n    stream.pipe(req);\n</code></pre>\n<p>Note that when you pipe to a request, superagent sends the piped data with <a href=\"https://en.wikipedia.org/wiki/Chunked_transfer_encoding\">chunked transfer encoding</a>, which isn&#39;t supported by all servers (for instance, Python WSGI servers).</p>\n<p>Or piping the response to a file:</p>\n<pre><code class=\"language-javascript\">    const stream = fs.createWriteStream(&#39;path/to/my.json&#39;);\n    const req = request.get(&#39;/some.json&#39;);\n    req.pipe(stream);\n</code></pre>\n<p> It&#39;s not possible to mix pipes and callbacks or promises. Note that you should <strong>NOT</strong> attempt to pipe the result of <code>.end()</code> or the <code>Response</code> object:</p>\n<pre><code class=\"language-javascript\">    // Don&#39;t do either of these:\n    const stream = getAWritableStream();\n    const req = request\n      .get(&#39;/some.json&#39;)\n      // BAD: this pipes garbage to the stream and fails in unexpected ways\n      .end((err, this_does_not_work) =&gt; this_does_not_work.pipe(stream))\n    const req = request\n      .get(&#39;/some.json&#39;)\n      .end()\n      // BAD: this is also unsupported, .pipe calls .end for you.\n      .pipe(nope_its_too_late);\n</code></pre>\n<p>In a <a href=\"https://github.com/ladjs/superagent/issues/1188\">future version</a> of superagent, improper calls to <code>pipe()</code> will fail.</p>\n<h2 id=\"multipart-requests\">Multipart requests</h2>\n<p>SuperAgent is also great for <em>building</em> multipart requests for which it provides methods <code>.attach()</code> and <code>.field()</code>.</p>\n<p>When you use <code>.field()</code> or <code>.attach()</code> you can&#39;t use <code>.send()</code> and you <em>must not</em> set <code>Content-Type</code> (the correct type will be set for you).</p>\n<h3 id=\"attaching-files\">Attaching files</h3>\n<p>To send a file use <code>.attach(name, [file], [options])</code>. You can attach multiple files by calling <code>.attach</code> multiple times. The arguments are:</p>\n<ul>\n<li><code>name</code> — field name in the form.</li>\n<li><code>file</code> — either string with file path or <code>Blob</code>/<code>Buffer</code> object.</li>\n<li><code>options</code> — (optional) either string with custom file name or <code>{filename: string}</code> object. In Node also <code>{contentType: &#39;mime/type&#39;}</code> is supported. In browser create a <code>Blob</code> with an appropriate type instead.</li>\n</ul>\n<br>\n\n<pre><code class=\"language-javascript\">    request\n      .post(&#39;/upload&#39;)\n      .attach(&#39;image1&#39;, &#39;path/to/felix.jpeg&#39;)\n      .attach(&#39;image2&#39;, imageBuffer, &#39;luna.jpeg&#39;)\n      .field(&#39;caption&#39;, &#39;My cats&#39;)\n      .then(callback);\n</code></pre>\n<h3 id=\"field-values\">Field values</h3>\n<p>Much like form fields in HTML, you can set field values with <code>.field(name, value)</code> and <code>.field({name: value})</code>. Suppose you want to upload a few images with your name and email, your request might look something like this:</p>\n<pre><code class=\"language-javascript\">     request\n       .post(&#39;/upload&#39;)\n       .field(&#39;user[name]&#39;, &#39;Tobi&#39;)\n       .field(&#39;user[email]&#39;, &#39;tobi@learnboost.com&#39;)\n       .field(&#39;friends[]&#39;, [&#39;loki&#39;, &#39;jane&#39;])\n       .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n       .then(callback);\n</code></pre>\n<h2 id=\"compression\">Compression</h2>\n<p>The node client supports compressed responses, best of all, you don&#39;t have to do anything! It just works.</p>\n<h2 id=\"buffering-responses\">Buffering responses</h2>\n<p>To force buffering of response bodies as <code>res.text</code> you may invoke <code>req.buffer()</code>. To undo the default of buffering for text responses such as &quot;text/plain&quot;, &quot;text/html&quot; etc you may invoke <code>req.buffer(false)</code>.</p>\n<p>When buffered the <code>res.buffered</code> flag is provided, you may use this to handle both buffered and unbuffered responses in the same callback.</p>\n<h2 id=\"cors\">CORS</h2>\n<p>For security reasons, browsers will block cross-origin requests unless the server opts-in using CORS headers. Browsers will also make extra <strong>OPTIONS</strong> requests to check what HTTP headers and methods are allowed by the server. <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS\">Read more about CORS</a>.</p>\n<p>The <code>.withCredentials()</code> method enables the ability to send cookies from the origin, however only when <code>Access-Control-Allow-Origin</code> is <em>not</em> a wildcard (&quot;*&quot;), and <code>Access-Control-Allow-Credentials</code> is &quot;true&quot;.</p>\n<pre><code class=\"language-javascript\">    request\n      .get(&#39;https://api.example.com:4001/&#39;)\n      .withCredentials()\n      .then(res =&gt; {\n        assert.equal(200, res.status);\n        assert.equal(&#39;tobi&#39;, res.text);\n      })\n</code></pre>\n<h2 id=\"error-handling\">Error handling</h2>\n<p>Your callback function will always be passed two arguments: error and response. If no error occurred, the first argument will be null:</p>\n<pre><code class=\"language-javascript\">    request\n     .post(&#39;/upload&#39;)\n     .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n     .then(res =&gt; {\n\n     });\n</code></pre>\n<p>An &quot;error&quot; event is also emitted, with you can listen for:</p>\n<pre><code class=\"language-javascript\">    request\n      .post(&#39;/upload&#39;)\n      .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)\n      .on(&#39;error&#39;, handle)\n      .then(res =&gt; {\n\n      });\n</code></pre>\n<p>Note that <strong>superagent considers 4xx and 5xx responses (as well as unhandled 3xx responses) errors by default</strong>. For example, if you get a <code>304 Not modified</code>, <code>403 Forbidden</code> or <code>500 Internal server error</code> response, this status information will be available via <code>err.status</code>. Errors from such responses also contain an <code>err.response</code> field with all of the properties mentioned in &quot;<a href=\"#response-properties\">Response properties</a>&quot;. The library behaves in this way to handle the common case of wanting success responses and treating HTTP error status codes as errors while still allowing for custom logic around specific error conditions.</p>\n<p>Network failures, timeouts, and other errors that produce no response will contain no <code>err.status</code> or <code>err.response</code> fields.</p>\n<p>If you wish to handle 404 or other HTTP error responses, you can query the <code>err.status</code> property. When an HTTP error occurs (4xx or 5xx response) the <code>res.error</code> property is an <code>Error</code> object, this allows you to perform checks such as:</p>\n<pre><code class=\"language-javascript\">    if (err &amp;&amp; err.status === 404) {\n      alert(&#39;oh no &#39; + res.body.message);\n    }\n    else if (err) {\n      // all other error types we handle generically\n    }\n</code></pre>\n<p>Alternatively, you can use the <code>.ok(callback)</code> method to decide whether a response is an error or not. The callback to the <code>ok</code> function gets a response and returns <code>true</code> if the response should be interpreted as success.</p>\n<pre><code class=\"language-javascript\">    request.get(&#39;/404&#39;)\n      .ok(res =&gt; res.status &lt; 500)\n      .then(response =&gt; {\n        // reads 404 page as a successful response\n      })\n</code></pre>\n<h2 id=\"progress-tracking\">Progress tracking</h2>\n<p>SuperAgent fires <code>progress</code> events on upload and download of large files.</p>\n<pre><code class=\"language-javascript\">    request.post(url)\n      .attach(&#39;field_name&#39;, file)\n      .on(&#39;progress&#39;, event =&gt; {\n        /* the event is:\n        {\n          direction: &quot;upload&quot; or &quot;download&quot;\n          percent: 0 to 100 // may be missing if file size is unknown\n          total: // total file size, may be missing\n          loaded: // bytes downloaded or uploaded so far\n        } */\n      })\n      .then()\n</code></pre>\n<h2 id=\"testing-on-localhost\">Testing on localhost</h2>\n<h3 id=\"forcing-specific-connection-ip-address\">Forcing specific connection IP address</h3>\n<p>In Node.js it&#39;s possible to ignore DNS resolution and direct all requests to a specific IP address using <code>.connect()</code> method. For example, this request will go to localhost instead of <code>example.com</code>:</p>\n<pre><code class=\"language-javascript\">    const res = await request.get(&quot;http://example.com&quot;).connect(&quot;127.0.0.1&quot;);\n</code></pre>\n<p>Because the request may be redirected, it&#39;s possible to specify multiple hostnames and multiple IPs, as well as a special <code>*</code> as the fallback (note: other wildcards are not supported). The requests will keep their <code>Host</code> header with the original value. <code>.connect(undefined)</code> turns off the feature.</p>\n<pre><code class=\"language-javascript\">    const res = await request.get(&quot;http://redir.example.com:555&quot;)\n      .connect({\n        &quot;redir.example.com&quot;: &quot;127.0.0.1&quot;, // redir.example.com:555 will use 127.0.0.1:555\n        &quot;www.example.com&quot;: false, // don&#39;t override this one; use DNS as normal\n        &quot;mapped.example.com&quot;: { host: &quot;127.0.0.1&quot;, port: 8080}, // mapped.example.com:* will use 127.0.0.1:8080\n        &quot;*&quot;: &quot;proxy.example.com&quot;, // all other requests will go to this host\n      });\n</code></pre>\n<h3 id=\"ignoring-brokeninsecure-https-on-localhost\">Ignoring broken/insecure HTTPS on localhost</h3>\n<p>In Node.js, when HTTPS is misconfigured and insecure (e.g. using self-signed certificate <em>without</em> specifying own <code>.ca()</code>), it&#39;s still possible to permit requests to <code>localhost</code> by calling <code>.trustLocalhost()</code>:</p>\n<pre><code class=\"language-javascript\">    const res = await request.get(&quot;https://localhost&quot;).trustLocalhost()\n</code></pre>\n<p>Together with <code>.connect(&quot;127.0.0.1&quot;)</code> this may be used to force HTTPS requests to any domain to be re-routed to <code>localhost</code> instead.</p>\n<p>It&#39;s generally safe to ignore broken HTTPS on <code>localhost</code>, because the loopback interface is not exposed to untrusted networks. Trusting <code>localhost</code> may become the default in the future. Use <code>.trustLocalhost(false)</code> to force check of <code>127.0.0.1</code>&#39;s authenticity.</p>\n<p>We intentionally don&#39;t support disabling of HTTPS security when making requests to any other IP, because such options end up abused as a quick &quot;fix&quot; for HTTPS problems. You can get free HTTPS certificates from <a href=\"https://certbot.eff.org\">Let&#39;s Encrypt</a> or set your own CA (<code>.ca(ca_public_pem)</code>) to make your self-signed certificates trusted.</p>\n<h2 id=\"promise-and-generator-support\">Promise and Generator support</h2>\n<p>SuperAgent&#39;s request is a &quot;thenable&quot; object that&#39;s compatible with JavaScript promises and the <code>async</code>/<code>await</code> syntax.</p>\n<pre><code class=\"language-javascript\">    const res = await request.get(url);\n</code></pre>\n<p>If you&#39;re using promises, <strong>do not</strong> call <code>.end()</code> or <code>.pipe()</code>. Any use of <code>.then()</code> or <code>await</code> disables all other ways of using the request.</p>\n<p>Libraries like <a href=\"https://github.com/tj/co\">co</a> or a web framework like <a href=\"https://github.com/koajs/koa\">koa</a> can <code>yield</code> on any SuperAgent method:</p>\n<pre><code class=\"language-javascript\">    const req = request\n      .get(&#39;http://local&#39;)\n      .auth(&#39;tobi&#39;, &#39;learnboost&#39;);\n    const res = yield req;\n</code></pre>\n<p>Note that SuperAgent expects the global <code>Promise</code> object to be present. You&#39;ll need to use v7 and a polyfill to use promises in Internet Explorer or Node.js 0.10.</p>\n<p>We have dropped support in v8 for IE.  You must add a polyfill for WeakRef and BigInt if you wish to support Opera 85, iOS Safari 12.2-12.5, for example using <a href=\"https://cdnjs.cloudflare.com/polyfill/\">https://cdnjs.cloudflare.com/polyfill/</a>:</p>\n<pre><code class=\"language-html\">&lt;script src=&quot;https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt&quot;&gt;&lt;/script&gt;\n</code></pre>\n<h2 id=\"browser-and-node-versions\">Browser and node versions</h2>\n<p>SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.</p>\n<p>If want to use WebPack to compile code for Node.JS, you <em>must</em> specify <a href=\"https://webpack.github.io/docs/configuration.html#target\">node target</a> in its configuration.</p>\n\n    </div>\n    <a href=\"http://github.com/ladjs/superagent\"><img style=\"position: absolute; top: 0; right: 0; border: 0;\" src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png\" alt=\"Fork me on GitHub\"></a>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js\"></script>\n    <script>\n      $('code').each(function(){\n        $(this).html(highlight($(this).text()));\n      });\n\n      function highlight(js) {\n        return js\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n          .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n          .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n          .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n      }\n    </script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js\"></script>\n    <script>\n      // Only use tocbot for main docs, not test docs\n      if (document.querySelector('#superagent')) {\n        tocbot.init({\n          // Where to render the table of contents.\n          tocSelector: '#menu',\n          // Where to grab the headings to build the table of contents.\n          contentSelector: '#content',\n          // Which headings to grab inside of the contentSelector element.\n          headingSelector: 'h2',\n          smoothScroll: false\n        });\n      }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"superagent\",\n  \"description\": \"elegant & feature rich browser / node HTTP with a fluent API\",\n  \"version\": \"10.3.0\",\n  \"author\": \"TJ Holowaychuk <tj@vision-media.ca>\",\n  \"browser\": {\n    \"./src/node/index.js\": \"./src/client.js\",\n    \"./lib/node/index.js\": \"./lib/client.js\",\n    \"./test/support/server.js\": \"./test/support/blank.js\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/ladjs/superagent/issues\"\n  },\n  \"contributors\": [\n    \"Kornel Lesiński <kornel@geekhood.net>\",\n    \"Peter Lyons <pete@peterlyons.com>\",\n    \"Hunter Loftis <hunter@hunterloftis.com>\",\n    \"Nick Baugh <niftylettuce@gmail.com>\"\n  ],\n  \"dependencies\": {\n    \"component-emitter\": \"^1.3.1\",\n    \"cookiejar\": \"^2.1.4\",\n    \"debug\": \"^4.3.7\",\n    \"fast-safe-stringify\": \"^2.1.1\",\n    \"form-data\": \"^4.0.5\",\n    \"formidable\": \"^3.5.4\",\n    \"methods\": \"^1.1.2\",\n    \"mime\": \"2.6.0\",\n    \"qs\": \"^6.14.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.20.7\",\n    \"@babel/core\": \"^7.20.12\",\n    \"@babel/plugin-transform-runtime\": \"^7.19.6\",\n    \"@babel/preset-env\": \"^7.20.2\",\n    \"@babel/runtime\": \"^7.20.13\",\n    \"@commitlint/cli\": \"^19.8.1\",\n    \"@commitlint/config-conventional\": \"^19.8.1\",\n    \"babelify\": \"^10.0.0\",\n    \"Base64\": \"^1.1.0\",\n    \"basic-auth-connect\": \"^1.0.0\",\n    \"body-parser\": \"^1.20.4\",\n    \"browserify\": \"^17.0.0\",\n    \"cookie-parser\": \"^1.4.7\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^8.32.0\",\n    \"eslint-config-xo-lass\": \"2\",\n    \"eslint-plugin-compat\": \"4.0.2\",\n    \"eslint-plugin-node\": \"^11.1.0\",\n    \"express\": \"^4.18.3\",\n    \"express-session\": \"^1.17.3\",\n    \"fixpack\": \"^4.0.0\",\n    \"get-port\": \"4.2.0\",\n    \"husky\": \"^9.1.7\",\n    \"lint-staged\": \"^15.5.2\",\n    \"marked\": \"^4.2.12\",\n    \"mocha\": \"^6.2.3\",\n    \"multer\": \"1.4.5-lts.1\",\n    \"nyc\": \"^15.1.0\",\n    \"remark-cli\": \"^11.0.0\",\n    \"remark-preset-github\": \"4.0.4\",\n    \"rimraf\": \"3\",\n    \"should\": \"^13.2.3\",\n    \"should-http\": \"^0.1.1\",\n    \"tinyify\": \"3.0.0\",\n    \"xo\": \"^0.53.1\",\n    \"zuul\": \"^3.12.0\"\n  },\n  \"engines\": {\n    \"node\": \">=14.18.0\"\n  },\n  \"files\": [\n    \"dist/*.js\",\n    \"lib/**/*.js\"\n  ],\n  \"homepage\": \"https://github.com/ladjs/superagent\",\n  \"jsdelivr\": \"dist/superagent.min.js\",\n  \"keywords\": [\n    \"agent\",\n    \"ajax\",\n    \"ajax\",\n    \"api\",\n    \"async\",\n    \"await\",\n    \"axios\",\n    \"cancel\",\n    \"client\",\n    \"frisbee\",\n    \"got\",\n    \"http\",\n    \"http\",\n    \"https\",\n    \"ky\",\n    \"promise\",\n    \"promise\",\n    \"promises\",\n    \"request\",\n    \"request\",\n    \"requests\",\n    \"response\",\n    \"rest\",\n    \"retry\",\n    \"super\",\n    \"superagent\",\n    \"timeout\",\n    \"transform\",\n    \"xhr\",\n    \"xmlhttprequest\"\n  ],\n  \"license\": \"MIT\",\n  \"main\": \"lib/node/index.js\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/ladjs/superagent.git\"\n  },\n  \"scripts\": {\n    \"browserify\": \"browserify src/node/index.js -o dist/superagent.js -s superagent -g [ babelify --configFile ./.dist.babelrc ]\",\n    \"build\": \"npm run build:clean && npm run build:lib && npm run build:dist\",\n    \"build:clean\": \"rimraf lib dist\",\n    \"build:dist\": \"npm run browserify && npm run minify\",\n    \"build:lib\": \"babel --config-file ./.lib.babelrc src --out-dir lib\",\n    \"build:test\": \"babel --config-file ./.test.babelrc test --out-dir lib/node/test\",\n    \"coverage\": \"nyc report --reporter=text-lcov > coverage.lcov\",\n    \"lint\": \"eslint -c .eslintrc src test && remark . -qfo && eslint -c .lib.eslintrc lib/**/*.js && eslint -c .dist.eslintrc dist/**/*.js\",\n    \"minify\": \"cross-env NODE_ENV=production browserify src/node/index.js -o dist/superagent.min.js -s superagent -g [ babelify --configFile ./.dist.babelrc ] -p tinyify\",\n    \"nyc\": \"cross-env NODE_ENV=test nyc ava\",\n    \"test\": \"npm run build && npm run lint && make test\",\n    \"test-http2\": \"npm run build && npm run lint && make test-node-http2\",\n    \"prepare\": \"husky\"\n  },\n  \"unpkg\": \"dist/superagent.min.js\"\n}\n"
  },
  {
    "path": "src/agent-base.js",
    "content": "const defaults = [\n  'use',\n  'on',\n  'once',\n  'set',\n  'query',\n  'type',\n  'accept',\n  'auth',\n  'withCredentials',\n  'sortQuery',\n  'retry',\n  'ok',\n  'redirects',\n  'timeout',\n  'buffer',\n  'serialize',\n  'parse',\n  'ca',\n  'key',\n  'pfx',\n  'cert',\n  'disableTLSCerts'\n]\n\nclass Agent {\n  constructor () {\n    this._defaults = [];\n  }\n\n  _setDefaults (request) {\n    for (const def of this._defaults) {\n      request[def.fn](...def.args);\n    }\n  }\n}\n\nfor (const fn of defaults) {\n  // Default setting for all requests from this agent\n  Agent.prototype[fn] = function (...args) {\n    this._defaults.push({ fn, args });\n    return this;\n  };\n}\n\n\nmodule.exports = Agent;\n"
  },
  {
    "path": "src/client.js",
    "content": "/**\n * Root reference for iframes.\n */\n\nlet root;\nif (typeof window !== 'undefined') {\n  // Browser window\n  root = window;\n} else if (typeof self === 'undefined') {\n  // Other environments\n  console.warn(\n    'Using browser-only version of superagent in non-browser environment'\n  );\n  root = this;\n} else {\n  // Web Worker\n  root = self;\n}\n\nconst Emitter = require('component-emitter');\nconst safeStringify = require('fast-safe-stringify');\nconst qs = require('qs');\nconst RequestBase = require('./request-base');\nconst { isObject, mixin, hasOwn } = require('./utils');\nconst ResponseBase = require('./response-base');\nconst Agent = require('./agent-base');\n\n/**\n * Noop.\n */\n\nfunction noop() {}\n\n/**\n * Expose `request`.\n */\n\nmodule.exports = function (method, url) {\n  // callback\n  if (typeof url === 'function') {\n    return new exports.Request('GET', method).end(url);\n  }\n\n  // url first\n  if (arguments.length === 1) {\n    return new exports.Request('GET', method);\n  }\n\n  return new exports.Request(method, url);\n};\n\nexports = module.exports;\n\nconst request = exports;\n\nexports.Request = Request;\n\n/**\n * Determine XHR.\n */\n\nrequest.getXHR = () => {\n  if (root.XMLHttpRequest) {\n    return new root.XMLHttpRequest();\n  }\n\n  throw new Error('Browser-only version of superagent could not find XHR');\n};\n\n/**\n * Removes leading and trailing whitespace, added to support IE.\n *\n * @param {String} s\n * @return {String}\n * @api private\n */\n\nconst trim = ''.trim ? (s) => s.trim() : (s) => s.replace(/(^\\s*|\\s*$)/g, '');\n\n/**\n * Serialize the given `obj`.\n *\n * @param {Object} obj\n * @return {String}\n * @api private\n */\n\nfunction serialize(object) {\n  if (!isObject(object)) return object;\n  const pairs = [];\n  for (const key in object) {\n    if (hasOwn(object, key)) pushEncodedKeyValuePair(pairs, key, object[key]);\n  }\n\n  return pairs.join('&');\n}\n\n/**\n * Helps 'serialize' with serializing arrays.\n * Mutates the pairs array.\n *\n * @param {Array} pairs\n * @param {String} key\n * @param {Mixed} val\n */\n\nfunction pushEncodedKeyValuePair(pairs, key, value) {\n  if (value === undefined) return;\n  if (value === null) {\n    pairs.push(encodeURI(key));\n    return;\n  }\n\n  if (Array.isArray(value)) {\n    for (const v of value) {\n      pushEncodedKeyValuePair(pairs, key, v);\n    }\n  } else if (isObject(value)) {\n    for (const subkey in value) {\n      if (hasOwn(value, subkey))\n        pushEncodedKeyValuePair(pairs, `${key}[${subkey}]`, value[subkey]);\n    }\n  } else {\n    pairs.push(encodeURI(key) + '=' + encodeURIComponent(value));\n  }\n}\n\n/**\n * Expose serialization method.\n */\n\nrequest.serializeObject = serialize;\n\n/**\n * Parse the given x-www-form-urlencoded `str`.\n *\n * @param {String} str\n * @return {Object}\n * @api private\n */\n\nfunction parseString(string_) {\n  const object = {};\n  const pairs = string_.split('&');\n  let pair;\n  let pos;\n\n  for (let i = 0, length_ = pairs.length; i < length_; ++i) {\n    pair = pairs[i];\n    pos = pair.indexOf('=');\n    if (pos === -1) {\n      object[decodeURIComponent(pair)] = '';\n    } else {\n      object[decodeURIComponent(pair.slice(0, pos))] = decodeURIComponent(\n        pair.slice(pos + 1)\n      );\n    }\n  }\n\n  return object;\n}\n\n/**\n * Expose parser.\n */\n\nrequest.parseString = parseString;\n\n/**\n * Default MIME type map.\n *\n *     superagent.types.xml = 'application/xml';\n *\n */\n\nrequest.types = {\n  html: 'text/html',\n  json: 'application/json',\n  xml: 'text/xml',\n  urlencoded: 'application/x-www-form-urlencoded',\n  form: 'application/x-www-form-urlencoded',\n  'form-data': 'application/x-www-form-urlencoded'\n};\n\n/**\n * Default serialization map.\n *\n *     superagent.serialize['application/xml'] = function(obj){\n *       return 'generated xml here';\n *     };\n *\n */\n\nrequest.serialize = {\n  'application/x-www-form-urlencoded': (obj) => {\n    return qs.stringify(obj, { indices: false, strictNullHandling: true });\n  },\n  'application/json': safeStringify\n};\n\n/**\n * Default parsers.\n *\n *     superagent.parse['application/xml'] = function(str){\n *       return { object parsed from str };\n *     };\n *\n */\n\nrequest.parse = {\n  'application/x-www-form-urlencoded': parseString,\n  'application/json': JSON.parse\n};\n\n/**\n * Parse the given header `str` into\n * an object containing the mapped fields.\n *\n * @param {String} str\n * @return {Object}\n * @api private\n */\n\nfunction parseHeader(string_) {\n  const lines = string_.split(/\\r?\\n/);\n  const fields = {};\n  let index;\n  let line;\n  let field;\n  let value;\n\n  for (let i = 0, length_ = lines.length; i < length_; ++i) {\n    line = lines[i];\n    index = line.indexOf(':');\n    if (index === -1) {\n      // could be empty line, just skip it\n      continue;\n    }\n\n    field = line.slice(0, index).toLowerCase();\n    value = trim(line.slice(index + 1));\n    fields[field] = value;\n  }\n\n  return fields;\n}\n\n/**\n * Check if `mime` is json or has +json structured syntax suffix.\n *\n * @param {String} mime\n * @return {Boolean}\n * @api private\n */\n\nfunction isJSON(mime) {\n  // should match /json or +json\n  // but not /json-seq\n  return /[/+]json($|[^-\\w])/i.test(mime);\n}\n\n/**\n * Initialize a new `Response` with the given `xhr`.\n *\n *  - set flags (.ok, .error, etc)\n *  - parse header\n *\n * Examples:\n *\n *  Aliasing `superagent` as `request` is nice:\n *\n *      request = superagent;\n *\n *  We can use the promise-like API, or pass callbacks:\n *\n *      request.get('/').end(function(res){});\n *      request.get('/', function(res){});\n *\n *  Sending data can be chained:\n *\n *      request\n *        .post('/user')\n *        .send({ name: 'tj' })\n *        .end(function(res){});\n *\n *  Or passed to `.send()`:\n *\n *      request\n *        .post('/user')\n *        .send({ name: 'tj' }, function(res){});\n *\n *  Or passed to `.post()`:\n *\n *      request\n *        .post('/user', { name: 'tj' })\n *        .end(function(res){});\n *\n * Or further reduced to a single call for simple cases:\n *\n *      request\n *        .post('/user', { name: 'tj' }, function(res){});\n *\n * @param {XMLHTTPRequest} xhr\n * @param {Object} options\n * @api private\n */\n\nfunction Response(request_) {\n  this.req = request_;\n  this.xhr = this.req.xhr;\n  // responseText is accessible only if responseType is '' or 'text' and on older browsers\n  this.text =\n    (this.req.method !== 'HEAD' &&\n      (this.xhr.responseType === '' || this.xhr.responseType === 'text')) ||\n    typeof this.xhr.responseType === 'undefined'\n      ? this.xhr.responseText\n      : null;\n  this.statusText = this.req.xhr.statusText;\n  let { status } = this.xhr;\n  // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request\n  if (status === 1223) {\n    status = 204;\n  }\n\n  this._setStatusProperties(status);\n  this.headers = parseHeader(this.xhr.getAllResponseHeaders());\n  this.header = this.headers;\n  // getAllResponseHeaders sometimes falsely returns \"\" for CORS requests, but\n  // getResponseHeader still works. so we get content-type even if getting\n  // other headers fails.\n  this.header['content-type'] = this.xhr.getResponseHeader('content-type');\n  this._setHeaderProperties(this.header);\n\n  if (this.text === null && request_._responseType) {\n    this.body = this.xhr.response;\n  } else {\n    this.body =\n      this.req.method === 'HEAD'\n        ? null\n        : this._parseBody(this.text ? this.text : this.xhr.response);\n  }\n}\n\nmixin(Response.prototype, ResponseBase.prototype);\n\n/**\n * Parse the given body `str`.\n *\n * Used for auto-parsing of bodies. Parsers\n * are defined on the `superagent.parse` object.\n *\n * @param {String} str\n * @return {Mixed}\n * @api private\n */\n\nResponse.prototype._parseBody = function (string_) {\n  let parse = request.parse[this.type];\n  if (this.req._parser) {\n    return this.req._parser(this, string_);\n  }\n\n  if (!parse && isJSON(this.type)) {\n    parse = request.parse['application/json'];\n  }\n\n  return parse && string_ && (string_.length > 0 || string_ instanceof Object)\n    ? parse(string_)\n    : null;\n};\n\n/**\n * Return an `Error` representative of this response.\n *\n * @return {Error}\n * @api public\n */\n\nResponse.prototype.toError = function () {\n  const { req } = this;\n  const { method } = req;\n  const { url } = req;\n\n  const message = `cannot ${method} ${url} (${this.status})`;\n  const error = new Error(message);\n  error.status = this.status;\n  error.method = method;\n  error.url = url;\n\n  return error;\n};\n\n/**\n * Expose `Response`.\n */\n\nrequest.Response = Response;\n\n/**\n * Initialize a new `Request` with the given `method` and `url`.\n *\n * @param {String} method\n * @param {String} url\n * @api public\n */\n\nfunction Request(method, url) {\n  const self = this;\n  this._query = this._query || [];\n  this.method = method;\n  this.url = url;\n  this.header = {}; // preserves header name case\n  this._header = {}; // coerces header names to lowercase\n  this.on('end', () => {\n    let error = null;\n    let res = null;\n\n    try {\n      res = new Response(self);\n    } catch (err) {\n      error = new Error('Parser is unable to parse the response');\n      error.parse = true;\n      error.original = err;\n      // issue #675: return the raw response if the response parsing fails\n      if (self.xhr) {\n        // ie9 doesn't have 'response' property\n        error.rawResponse =\n          typeof self.xhr.responseType === 'undefined'\n            ? self.xhr.responseText\n            : self.xhr.response;\n        // issue #876: return the http status code if the response parsing fails\n        error.status = self.xhr.status ? self.xhr.status : null;\n        error.statusCode = error.status; // backwards-compat only\n      } else {\n        error.rawResponse = null;\n        error.status = null;\n      }\n\n      return self.callback(error);\n    }\n\n    self.emit('response', res);\n\n    let new_error;\n    try {\n      if (!self._isResponseOK(res)) {\n        new_error = new Error(\n          res.statusText || res.text || 'Unsuccessful HTTP response'\n        );\n      }\n    } catch (err) {\n      new_error = err; // ok() callback can throw\n    }\n\n    // #1000 don't catch errors from the callback to avoid double calling it\n    if (new_error) {\n      new_error.original = error;\n      new_error.response = res;\n      new_error.status = new_error.status || res.status;\n      self.callback(new_error, res);\n    } else {\n      self.callback(null, res);\n    }\n  });\n}\n\n/**\n * Mixin `Emitter` and `RequestBase`.\n */\n\n// eslint-disable-next-line new-cap\nEmitter(Request.prototype);\n\nmixin(Request.prototype, RequestBase.prototype);\n\n/**\n * Set Content-Type to `type`, mapping values from `request.types`.\n *\n * Examples:\n *\n *      superagent.types.xml = 'application/xml';\n *\n *      request.post('/')\n *        .type('xml')\n *        .send(xmlstring)\n *        .end(callback);\n *\n *      request.post('/')\n *        .type('application/xml')\n *        .send(xmlstring)\n *        .end(callback);\n *\n * @param {String} type\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.type = function (type) {\n  this.set('Content-Type', request.types[type] || type);\n  return this;\n};\n\n/**\n * Set Accept to `type`, mapping values from `request.types`.\n *\n * Examples:\n *\n *      superagent.types.json = 'application/json';\n *\n *      request.get('/agent')\n *        .accept('json')\n *        .end(callback);\n *\n *      request.get('/agent')\n *        .accept('application/json')\n *        .end(callback);\n *\n * @param {String} accept\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.accept = function (type) {\n  this.set('Accept', request.types[type] || type);\n  return this;\n};\n\n/**\n * Set Authorization field value with `user` and `pass`.\n *\n * @param {String} user\n * @param {String} [pass] optional in case of using 'bearer' as type\n * @param {Object} options with 'type' property 'auto', 'basic' or 'bearer' (default 'basic')\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.auth = function (user, pass, options) {\n  if (arguments.length === 1) pass = '';\n  if (typeof pass === 'object' && pass !== null) {\n    // pass is optional and can be replaced with options\n    options = pass;\n    pass = '';\n  }\n\n  if (!options) {\n    options = {\n      type: typeof btoa === 'function' ? 'basic' : 'auto'\n    };\n  }\n\n  const encoder = options.encoder\n    ? options.encoder\n    : (string) => {\n        if (typeof btoa === 'function') {\n          return btoa(string);\n        }\n\n        throw new Error('Cannot use basic auth, btoa is not a function');\n      };\n\n  return this._auth(user, pass, options, encoder);\n};\n\n/**\n * Add query-string `val`.\n *\n * Examples:\n *\n *   request.get('/shoes')\n *     .query('size=10')\n *     .query({ color: 'blue' })\n *\n * @param {Object|String} val\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.query = function (value) {\n  if (typeof value !== 'string') value = serialize(value);\n  if (value) this._query.push(value);\n  return this;\n};\n\n/**\n * Queue the given `file` as an attachment to the specified `field`,\n * with optional `options` (or filename).\n *\n * ``` js\n * request.post('/upload')\n *   .attach('content', new Blob(['<a id=\"a\"><b id=\"b\">hey!</b></a>'], { type: \"text/html\"}))\n *   .end(callback);\n * ```\n *\n * @param {String} field\n * @param {Blob|File} file\n * @param {String|Object} options\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.attach = function (field, file, options) {\n  if (file) {\n    if (this._data) {\n      throw new Error(\"superagent can't mix .send() and .attach()\");\n    }\n\n    this._getFormData().append(field, file, options || file.name);\n  }\n\n  return this;\n};\n\nRequest.prototype._getFormData = function () {\n  if (!this._formData) {\n    this._formData = new root.FormData();\n  }\n\n  return this._formData;\n};\n\n/**\n * Invoke the callback with `err` and `res`\n * and handle arity check.\n *\n * @param {Error} err\n * @param {Response} res\n * @api private\n */\n\nRequest.prototype.callback = function (error, res) {\n  if (this._shouldRetry(error, res)) {\n    return this._retry();\n  }\n\n  const fn = this._callback;\n  this.clearTimeout();\n\n  if (error) {\n    if (this._maxRetries) error.retries = this._retries - 1;\n    this.emit('error', error);\n  }\n\n  fn(error, res);\n};\n\n/**\n * Invoke callback with x-domain error.\n *\n * @api private\n */\n\nRequest.prototype.crossDomainError = function () {\n  const error = new Error(\n    'Request has been terminated\\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'\n  );\n  error.crossDomain = true;\n\n  error.status = this.status;\n  error.method = this.method;\n  error.url = this.url;\n\n  this.callback(error);\n};\n\n// This only warns, because the request is still likely to work\nRequest.prototype.agent = function () {\n  console.warn('This is not supported in browser version of superagent');\n  return this;\n};\n\nRequest.prototype.ca = Request.prototype.agent;\nRequest.prototype.buffer = Request.prototype.ca;\n\n// This throws, because it can't send/receive data as expected\nRequest.prototype.write = () => {\n  throw new Error(\n    'Streaming is not supported in browser version of superagent'\n  );\n};\n\nRequest.prototype.pipe = Request.prototype.write;\n\n/**\n * Check if `obj` is a host object,\n * we don't want to serialize these :)\n *\n * @param {Object} obj host object\n * @return {Boolean} is a host object\n * @api private\n */\nRequest.prototype._isHost = function (object) {\n  // Native objects stringify to [object File], [object Blob], [object FormData], etc.\n  return (\n    object &&\n    typeof object === 'object' &&\n    !Array.isArray(object) &&\n    Object.prototype.toString.call(object) !== '[object Object]'\n  );\n};\n\n/**\n * Initiate request, invoking callback `fn(res)`\n * with an instanceof `Response`.\n *\n * @param {Function} fn\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.end = function (fn) {\n  if (this._endCalled) {\n    console.warn(\n      'Warning: .end() was called twice. This is not supported in superagent'\n    );\n  }\n\n  this._endCalled = true;\n\n  // store callback\n  this._callback = fn || noop;\n\n  // querystring\n  this._finalizeQueryString();\n\n  this._end();\n};\n\nRequest.prototype._setUploadTimeout = function () {\n  const self = this;\n\n  // upload timeout it's wokrs only if deadline timeout is off\n  if (this._uploadTimeout && !this._uploadTimeoutTimer) {\n    this._uploadTimeoutTimer = setTimeout(() => {\n      self._timeoutError(\n        'Upload timeout of ',\n        self._uploadTimeout,\n        'ETIMEDOUT'\n      );\n    }, this._uploadTimeout);\n  }\n};\n\n// eslint-disable-next-line complexity\nRequest.prototype._end = function () {\n  if (this._aborted)\n    return this.callback(\n      new Error('The request has been aborted even before .end() was called')\n    );\n\n  const self = this;\n  this.xhr = request.getXHR();\n  const { xhr } = this;\n  let data = this._formData || this._data;\n\n  this._setTimeouts();\n\n  // state change\n  xhr.addEventListener('readystatechange', () => {\n    const { readyState } = xhr;\n    if (readyState >= 2 && self._responseTimeoutTimer) {\n      clearTimeout(self._responseTimeoutTimer);\n    }\n\n    if (readyState !== 4) {\n      return;\n    }\n\n    // In IE9, reads to any property (e.g. status) off of an aborted XHR will\n    // result in the error \"Could not complete the operation due to error c00c023f\"\n    let status;\n    try {\n      status = xhr.status;\n    } catch (err) {\n      status = 0;\n    }\n\n    if (!status) {\n      if (self.timedout || self._aborted) return;\n      return self.crossDomainError();\n    }\n\n    self.emit('end');\n  });\n\n  // progress\n  const handleProgress = (direction, e) => {\n    if (e.total > 0) {\n      e.percent = (e.loaded / e.total) * 100;\n\n      if (e.percent === 100) {\n        clearTimeout(self._uploadTimeoutTimer);\n      }\n    }\n\n    e.direction = direction;\n    self.emit('progress', e);\n  };\n\n  if (this.hasListeners('progress')) {\n    try {\n      xhr.addEventListener('progress', handleProgress.bind(null, 'download'));\n      if (xhr.upload) {\n        xhr.upload.addEventListener(\n          'progress',\n          handleProgress.bind(null, 'upload')\n        );\n      }\n    } catch (err) {\n      // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.\n      // Reported here:\n      // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context\n    }\n  }\n\n  if (xhr.upload) {\n    this._setUploadTimeout();\n  }\n\n  // initiate request\n  try {\n    if (this.username && this.password) {\n      xhr.open(this.method, this.url, true, this.username, this.password);\n    } else {\n      xhr.open(this.method, this.url, true);\n    }\n  } catch (err) {\n    // see #1149\n    return this.callback(err);\n  }\n\n  // CORS\n  if (this._withCredentials) xhr.withCredentials = true;\n\n  // body\n  if (\n    !this._formData &&\n    this.method !== 'GET' &&\n    this.method !== 'HEAD' &&\n    typeof data !== 'string' &&\n    !this._isHost(data)\n  ) {\n    // serialize stuff\n    const contentType = this._header['content-type'];\n    let serialize =\n      this._serializer ||\n      request.serialize[contentType ? contentType.split(';')[0] : ''];\n    if (!serialize && isJSON(contentType)) {\n      serialize = request.serialize['application/json'];\n    }\n\n    if (serialize) data = serialize(data);\n  }\n\n  // set header fields\n  for (const field in this.header) {\n    if (this.header[field] === null) continue;\n\n    if (hasOwn(this.header, field))\n      xhr.setRequestHeader(field, this.header[field]);\n  }\n\n  if (this._responseType) {\n    xhr.responseType = this._responseType;\n  }\n\n  // send stuff\n  this.emit('request', this);\n\n  // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing)\n  // We need null here if data is undefined\n  xhr.send(typeof data === 'undefined' ? null : data);\n};\n\n// create a Proxy that can instantiate a new Agent without using `new` keyword\n// (for backward compatibility and chaining)\nconst proxyAgent = new Proxy(Agent, {\n  apply(target, thisArg, argumentsList) {\n    return new target(...argumentsList);\n  }\n});\nrequest.agent = proxyAgent;\n\nfor (const method of ['GET', 'POST', 'OPTIONS', 'PATCH', 'PUT', 'DELETE']) {\n  Agent.prototype[method.toLowerCase()] = function (url, fn) {\n    const request_ = new request.Request(method, url);\n    this._setDefaults(request_);\n    if (fn) {\n      request_.end(fn);\n    }\n\n    return request_;\n  };\n}\n\nAgent.prototype.del = Agent.prototype.delete;\n\n/**\n * GET `url` with optional callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed|Function} [data] or fn\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.get = (url, data, fn) => {\n  const request_ = request('GET', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.query(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n\n/**\n * HEAD `url` with optional callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed|Function} [data] or fn\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.head = (url, data, fn) => {\n  const request_ = request('HEAD', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.query(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n\n/**\n * OPTIONS query to `url` with optional callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed|Function} [data] or fn\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.options = (url, data, fn) => {\n  const request_ = request('OPTIONS', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.send(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n\n/**\n * DELETE `url` with optional `data` and callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed} [data]\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nfunction del(url, data, fn) {\n  const request_ = request('DELETE', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.send(data);\n  if (fn) request_.end(fn);\n  return request_;\n}\n\nrequest.del = del;\nrequest.delete = del;\n\n/**\n * PATCH `url` with optional `data` and callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed} [data]\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.patch = (url, data, fn) => {\n  const request_ = request('PATCH', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.send(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n\n/**\n * POST `url` with optional `data` and callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed} [data]\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.post = (url, data, fn) => {\n  const request_ = request('POST', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.send(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n\n/**\n * PUT `url` with optional `data` and callback `fn(res)`.\n *\n * @param {String} url\n * @param {Mixed|Function} [data] or fn\n * @param {Function} [fn]\n * @return {Request}\n * @api public\n */\n\nrequest.put = (url, data, fn) => {\n  const request_ = request('PUT', url);\n  if (typeof data === 'function') {\n    fn = data;\n    data = null;\n  }\n\n  if (data) request_.send(data);\n  if (fn) request_.end(fn);\n  return request_;\n};\n"
  },
  {
    "path": "src/node/agent.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst { CookieJar } = require('cookiejar');\nconst { CookieAccessInfo } = require('cookiejar');\nconst methods = require('methods');\nconst request = require('../..');\nconst AgentBase = require('../agent-base');\n\n/**\n * Initialize a new `Agent`.\n *\n * @api public\n */\n\nclass Agent extends AgentBase {\n  constructor (options) {\n    super();\n\n    this.jar = new CookieJar();\n\n    if (options) {\n      if (options.ca) {\n        this.ca(options.ca);\n      }\n\n      if (options.key) {\n        this.key(options.key);\n      }\n\n      if (options.pfx) {\n        this.pfx(options.pfx);\n      }\n\n      if (options.cert) {\n        this.cert(options.cert);\n      }\n\n      if (options.rejectUnauthorized === false) {\n        this.disableTLSCerts();\n      }\n    }\n  }\n\n  /**\n   * Save the cookies in the given `res` to\n   * the agent's cookie jar for persistence.\n   *\n   * @param {Response} res\n   * @api private\n   */\n  _saveCookies (res) {\n    const cookies = res.headers['set-cookie'];\n    if (cookies) {\n      const url = new URL(res.request?.url || '');\n      this.jar.setCookies(cookies, url.hostname, url.pathname);\n    }\n  }\n\n  /**\n   * Attach cookies when available to the given `req`.\n   *\n   * @param {Request} req\n   * @api private\n   */\n  _attachCookies (request_) {\n    const url = new URL(request_.url);\n    const access = new CookieAccessInfo(\n      url.hostname,\n      url.pathname,\n      url.protocol === 'https:'\n    );\n    const cookies = this.jar.getCookies(access).toValueString();\n    request_.cookies = cookies;\n  }\n}\n\nfor (const name of methods) {\n  const method = name.toUpperCase();\n  if (method === \"QUERY\") continue;\n  Agent.prototype[name] = function (url, fn) {\n    const request_ = new request.Request(method, url);\n\n    request_.on('response', this._saveCookies.bind(this));\n    request_.on('redirect', this._saveCookies.bind(this));\n    request_.on('redirect', this._attachCookies.bind(this, request_));\n    this._setDefaults(request_);\n    this._attachCookies(request_);\n\n    if (fn) {\n      request_.end(fn);\n    }\n\n    return request_;\n  };\n}\n\nAgent.prototype.del = Agent.prototype.delete;\n\n// create a Proxy that can instantiate a new Agent without using `new` keyword\n// (for backward compatibility and chaining)\nconst proxyAgent = new Proxy(Agent, {\n  apply (target, thisArg, argumentsList) {\n    return new target(...argumentsList);\n  }\n});\n\nmodule.exports = proxyAgent;\n"
  },
  {
    "path": "src/node/decompress.js",
    "content": "const zlib = require('zlib');\nconst utils = require('../utils');\nconst { isGzipOrDeflateEncoding, isBrotliEncoding } = utils;\n\nexports.chooseDecompresser = (res) => {\n  let decompresser;\n  if (isGzipOrDeflateEncoding(res)) {\n    decompresser = zlib.createUnzip();\n  } else if (isBrotliEncoding(res)) {\n    decompresser = zlib.createBrotliDecompress();\n  } else {\n    throw new Error('unknown content-encoding');\n  }\n  return decompresser;\n}\n"
  },
  {
    "path": "src/node/http2wrapper.js",
    "content": "const http2 = require('http2');\nconst Stream = require('stream');\nconst net = require('net');\nconst tls = require('tls');\n\nconst {\n  HTTP2_HEADER_PATH,\n  HTTP2_HEADER_STATUS,\n  HTTP2_HEADER_METHOD,\n  HTTP2_HEADER_AUTHORITY,\n  HTTP2_HEADER_HOST,\n  HTTP2_HEADER_SET_COOKIE,\n  NGHTTP2_CANCEL\n} = http2.constants;\n\nfunction setProtocol(protocol) {\n  return {\n    request(options) {\n      return new Request(protocol, options);\n    }\n  };\n}\n\nfunction normalizeIpv6Host(host) {\n  return net.isIP(host) === 6 ? `[${host}]` : host;\n}\n\nclass Request extends Stream {\n  constructor(protocol, options) {\n    super();\n    const defaultPort = protocol === 'https:' ? 443 : 80;\n    const defaultHost = 'localhost';\n    const port = options.port || defaultPort;\n    const host = options.host || defaultHost;\n\n    delete options.port;\n    delete options.host;\n\n    this.method = options.method;\n    this.path = options.path;\n    this.protocol = protocol;\n    this.host = host;\n\n    delete options.method;\n    delete options.path;\n\n    const sessionOptions = { ...options };\n    if (options.socketPath) {\n      sessionOptions.socketPath = options.socketPath;\n      sessionOptions.createConnection = this.createUnixConnection.bind(this);\n    }\n\n    this._headers = {};\n\n    const normalizedHost = normalizeIpv6Host(host);\n    const session = http2.connect(\n      `${protocol}//${normalizedHost}:${port}`,\n      sessionOptions\n    );\n    this.setHeader('host', `${normalizedHost}:${port}`);\n\n    session.on('error', (error) => this.emit('error', error));\n\n    this.session = session;\n  }\n\n  createUnixConnection(authority, options) {\n    switch (this.protocol) {\n      case 'http:':\n        return net.connect(options.socketPath);\n      case 'https:':\n        options.ALPNProtocols = ['h2'];\n        options.servername = this.host;\n        options.allowHalfOpen = true;\n        return tls.connect(options.socketPath, options);\n      default:\n        throw new Error('Unsupported protocol', this.protocol);\n    }\n  }\n\n  setNoDelay(bool) {\n    // We can not use setNoDelay with HTTP/2.\n    // Node 10 limits http2session.socket methods to ones safe to use with HTTP/2.\n    // See also https://nodejs.org/api/http2.html#http2_http2session_socket\n  }\n\n  getFrame() {\n    if (this.frame) {\n      return this.frame;\n    }\n\n    const method = {\n      [HTTP2_HEADER_PATH]: this.path,\n      [HTTP2_HEADER_METHOD]: this.method\n    };\n\n    let headers = this.mapToHttp2Header(this._headers);\n\n    headers = Object.assign(headers, method);\n\n    const frame = this.session.request(headers);\n\n    frame.once('response', (headers, flags) => {\n      headers = this.mapToHttpHeader(headers);\n      frame.headers = headers;\n      frame.statusCode = headers[HTTP2_HEADER_STATUS];\n      frame.status = frame.statusCode;\n      this.emit('response', frame);\n    });\n\n    this._headerSent = true;\n\n    frame.once('drain', () => this.emit('drain'));\n    frame.on('error', (error) => this.emit('error', error));\n    frame.on('close', () => this.session.close());\n\n    this.frame = frame;\n    return frame;\n  }\n\n  mapToHttpHeader(headers) {\n    const keys = Object.keys(headers);\n    const http2Headers = {};\n    for (let key of keys) {\n      let value = headers[key];\n      key = key.toLowerCase();\n      switch (key) {\n        case HTTP2_HEADER_SET_COOKIE:\n          value = Array.isArray(value) ? value : [value];\n          break;\n        default:\n          break;\n      }\n\n      http2Headers[key] = value;\n    }\n\n    return http2Headers;\n  }\n\n  mapToHttp2Header(headers) {\n    const keys = Object.keys(headers);\n    const http2Headers = {};\n    for (let key of keys) {\n      let value = headers[key];\n      key = key.toLowerCase();\n      switch (key) {\n        case HTTP2_HEADER_HOST:\n          key = HTTP2_HEADER_AUTHORITY;\n          value = /^http:\\/\\/|^https:\\/\\//.test(value)\n            ? new URL(value).host\n            : value;\n          break;\n        default:\n          break;\n      }\n\n      http2Headers[key] = value;\n    }\n\n    return http2Headers;\n  }\n\n  setHeader(name, value) {\n    this._headers[name.toLowerCase()] = value;\n  }\n\n  getHeader(name) {\n    return this._headers[name.toLowerCase()];\n  }\n\n  write(data, encoding) {\n    const frame = this.getFrame();\n    return frame.write(data, encoding);\n  }\n\n  pipe(stream, options) {\n    const frame = this.getFrame();\n    return frame.pipe(stream, options);\n  }\n\n  end(data) {\n    const frame = this.getFrame();\n    frame.end(data);\n  }\n\n  abort(data) {\n    const frame = this.getFrame();\n    frame.close(NGHTTP2_CANCEL);\n    this.session.destroy();\n  }\n}\n\nexports.setProtocol = setProtocol;\n"
  },
  {
    "path": "src/node/index.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst { format } = require('url');\nconst Stream = require('stream');\nconst https = require('https');\nconst http = require('http');\nconst fs = require('fs');\nconst zlib = require('zlib');\nconst util = require('util');\nconst qs = require('qs');\nconst mime = require('mime');\nlet methods = require('methods');\nconst FormData = require('form-data');\nconst formidable = require('formidable');\nconst debug = require('debug')('superagent');\nconst CookieJar = require('cookiejar');\nconst safeStringify = require('fast-safe-stringify');\n\nconst utils = require('../utils');\nconst RequestBase = require('../request-base');\nconst http2 = require('./http2wrapper');\nconst { decompress } = require('./unzip');\nconst Response = require('./response');\n\nconst { mixin, hasOwn, isBrotliEncoding, isGzipOrDeflateEncoding } = utils;\nconst { chooseDecompresser } = require('./decompress');\n\nfunction request(method, url) {\n  // callback\n  if (typeof url === 'function') {\n    return new exports.Request('GET', method).end(url);\n  }\n\n  // url first\n  if (arguments.length === 1) {\n    return new exports.Request('GET', method);\n  }\n\n  return new exports.Request(method, url);\n}\n\nmodule.exports = request;\nexports = module.exports;\n\n/**\n * Expose `Request`.\n */\n\nexports.Request = Request;\n\n/**\n * Expose the agent function\n */\n\nexports.agent = require('./agent');\n\n/**\n * Noop.\n */\n\nfunction noop() {}\n\n/**\n * Expose `Response`.\n */\n\nexports.Response = Response;\n\n/**\n * Define \"form\" mime type.\n */\n\nmime.define(\n  {\n    'application/x-www-form-urlencoded': ['form', 'urlencoded', 'form-data']\n  },\n  true\n);\n\n/**\n * Protocol map.\n */\n\nexports.protocols = {\n  'http:': http,\n  'https:': https,\n  'http2:': http2\n};\n\n/**\n * Default serialization map.\n *\n *     superagent.serialize['application/xml'] = function(obj){\n *       return 'generated xml here';\n *     };\n *\n */\n\nexports.serialize = {\n  'application/x-www-form-urlencoded': (obj) => {\n    return qs.stringify(obj, { indices: false, strictNullHandling: true });\n  },\n  'application/json': safeStringify\n};\n\n/**\n * Default parsers.\n *\n *     superagent.parse['application/xml'] = function(res, fn){\n *       fn(null, res);\n *     };\n *\n */\n\nexports.parse = require('./parsers');\n\n/**\n * Default buffering map. Can be used to set certain\n * response types to buffer/not buffer.\n *\n *     superagent.buffer['application/xml'] = true;\n */\nexports.buffer = {};\n\n/**\n * Initialize internal header tracking properties on a request instance.\n *\n * @param {Object} req the instance\n * @api private\n */\nfunction _initHeaders(request_) {\n  request_._header = {\n    // coerces header names to lowercase\n  };\n  request_.header = {\n    // preserves header name case\n  };\n}\n\n/**\n * Initialize a new `Request` with the given `method` and `url`.\n *\n * @param {String} method\n * @param {String|Object} url\n * @api public\n */\n\nfunction Request(method, url) {\n  Stream.call(this);\n  if (typeof url !== 'string') url = format(url);\n  this._enableHttp2 = Boolean(process.env.HTTP2_TEST); // internal only\n  this._agent = false;\n  this._formData = null;\n  this.method = method;\n  this.url = url;\n  _initHeaders(this);\n  this.writable = true;\n  this._redirects = 0;\n  this.redirects(method === 'HEAD' ? 0 : 5);\n  this.cookies = '';\n  this.qs = {};\n  this._query = [];\n  this.qsRaw = this._query; // Unused, for backwards compatibility only\n  this._redirectList = [];\n  this._streamRequest = false;\n  this._lookup = undefined;\n  this.once('end', this.clearTimeout.bind(this));\n}\n\n/**\n * Inherit from `Stream` (which inherits from `EventEmitter`).\n * Mixin `RequestBase`.\n */\nutil.inherits(Request, Stream);\n\nmixin(Request.prototype, RequestBase.prototype);\n\n/**\n * Enable or Disable http2.\n *\n * Enable http2.\n *\n * ``` js\n * request.get('http://localhost/')\n *   .http2()\n *   .end(callback);\n *\n * request.get('http://localhost/')\n *   .http2(true)\n *   .end(callback);\n * ```\n *\n * Disable http2.\n *\n * ``` js\n * request = request.http2();\n * request.get('http://localhost/')\n *   .http2(false)\n *   .end(callback);\n * ```\n *\n * @param {Boolean} enable\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.http2 = function (bool) {\n  if (exports.protocols['http2:'] === undefined) {\n    throw new Error(\n      'superagent: this version of Node.js does not support http2'\n    );\n  }\n\n  this._enableHttp2 = bool === undefined ? true : bool;\n  return this;\n};\n\n/**\n * Queue the given `file` as an attachment to the specified `field`,\n * with optional `options` (or filename).\n *\n * ``` js\n * request.post('http://localhost/upload')\n *   .attach('field', Buffer.from('<b>Hello world</b>'), 'hello.html')\n *   .end(callback);\n * ```\n *\n * A filename may also be used:\n *\n * ``` js\n * request.post('http://localhost/upload')\n *   .attach('files', 'image.jpg')\n *   .end(callback);\n * ```\n *\n * @param {String} field\n * @param {String|fs.ReadStream|Buffer} file\n * @param {String|Object} options\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.attach = function (field, file, options) {\n  if (file) {\n    if (this._data) {\n      throw new Error(\"superagent can't mix .send() and .attach()\");\n    }\n\n    let o = options || {};\n    if (typeof options === 'string') {\n      o = { filename: options };\n    }\n\n    if (typeof file === 'string') {\n      if (!o.filename) o.filename = file;\n      debug('creating `fs.ReadStream` instance for file: %s', file);\n      file = fs.createReadStream(file);\n      file.on('error', (error) => {\n        const formData = this._getFormData();\n        formData.emit('error', error);\n      });\n    } else if (!o.filename && file.path) {\n      o.filename = file.path;\n    }\n\n    this._getFormData().append(field, file, o);\n  }\n\n  return this;\n};\n\nRequest.prototype._getFormData = function () {\n  if (!this._formData) {\n    this._formData = new FormData();\n    this._formData.on('error', (error) => {\n      debug('FormData error', error);\n      if (this.called) {\n        // The request has already finished and the callback was called.\n        // Silently ignore the error.\n        return;\n      }\n\n      this.callback(error);\n      this.abort();\n    });\n  }\n\n  return this._formData;\n};\n\n/**\n * Gets/sets the `Agent` to use for this HTTP request. The default (if this\n * function is not called) is to opt out of connection pooling (`agent: false`).\n *\n * @param {http.Agent} agent\n * @return {http.Agent}\n * @api public\n */\n\nRequest.prototype.agent = function (agent) {\n  if (arguments.length === 0) return this._agent;\n  this._agent = agent;\n  return this;\n};\n\n/**\n * Gets/sets the `lookup` function to use custom DNS resolver.\n *\n * @param {Function} lookup\n * @return {Function}\n * @api public\n */\n\nRequest.prototype.lookup = function (lookup) {\n  if (arguments.length === 0) return this._lookup;\n  this._lookup = lookup;\n  return this;\n};\n\n/**\n * Set _Content-Type_ response header passed through `mime.getType()`.\n *\n * Examples:\n *\n *      request.post('/')\n *        .type('xml')\n *        .send(xmlstring)\n *        .end(callback);\n *\n *      request.post('/')\n *        .type('json')\n *        .send(jsonstring)\n *        .end(callback);\n *\n *      request.post('/')\n *        .type('application/json')\n *        .send(jsonstring)\n *        .end(callback);\n *\n * @param {String} type\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.type = function (type) {\n  return this.set(\n    'Content-Type',\n    type.includes('/') ? type : mime.getType(type)\n  );\n};\n\n/**\n * Set _Accept_ response header passed through `mime.getType()`.\n *\n * Examples:\n *\n *      superagent.types.json = 'application/json';\n *\n *      request.get('/agent')\n *        .accept('json')\n *        .end(callback);\n *\n *      request.get('/agent')\n *        .accept('application/json')\n *        .end(callback);\n *\n * @param {String} accept\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.accept = function (type) {\n  return this.set('Accept', type.includes('/') ? type : mime.getType(type));\n};\n\n/**\n * Add query-string `val`.\n *\n * Examples:\n *\n *   request.get('/shoes')\n *     .query('size=10')\n *     .query({ color: 'blue' })\n *\n * @param {Object|String} val\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.query = function (value) {\n  if (typeof value === 'string') {\n    this._query.push(value);\n  } else {\n    Object.assign(this.qs, value);\n  }\n\n  return this;\n};\n\n/**\n * Write raw `data` / `encoding` to the socket.\n *\n * @param {Buffer|String} data\n * @param {String} encoding\n * @return {Boolean}\n * @api public\n */\n\nRequest.prototype.write = function (data, encoding) {\n  const request_ = this.request();\n  if (!this._streamRequest) {\n    this._streamRequest = true;\n  }\n\n  return request_.write(data, encoding);\n};\n\n/**\n * Pipe the request body to `stream`.\n *\n * @param {Stream} stream\n * @param {Object} options\n * @return {Stream}\n * @api public\n */\n\nRequest.prototype.pipe = function (stream, options) {\n  this.piped = true; // HACK...\n  this.buffer(false);\n  this.end();\n  return this._pipeContinue(stream, options);\n};\n\nRequest.prototype._pipeContinue = function (stream, options) {\n  this.req.once('response', (res) => {\n    // redirect\n    if (\n      isRedirect(res.statusCode) &&\n      this._redirects++ !== this._maxRedirects\n    ) {\n      return this._redirect(res) === this\n        ? this._pipeContinue(stream, options)\n        : undefined;\n    }\n\n    this.res = res;\n    this._emitResponse();\n    if (this._aborted) return;\n\n    if (this._shouldDecompress(res)) {\n\n      let decompresser = chooseDecompresser(res);\n\n      decompresser.on('error', (error) => {\n        if (error && error.code === 'Z_BUF_ERROR') {\n          // unexpected end of file is ignored by browsers and curl\n          stream.emit('end');\n          return;\n        }\n\n        stream.emit('error', error);\n      });\n      res.pipe(decompresser).pipe(stream, options);\n      // don't emit 'end' until decompresser has completed writing all its data.\n      decompresser.once('end', () => this.emit('end'));\n    } else {\n      res.pipe(stream, options);\n      res.once('end', () => this.emit('end'));\n    }\n  });\n  return stream;\n};\n\n/**\n * Enable / disable buffering.\n *\n * @return {Boolean} [val]\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.buffer = function (value) {\n  this._buffer = value !== false;\n  return this;\n};\n\n/**\n * Redirect to `url\n *\n * @param {IncomingMessage} res\n * @return {Request} for chaining\n * @api private\n */\n\nRequest.prototype._redirect = function (res) {\n  let url = res.headers.location;\n  if (!url) {\n    return this.callback(new Error('No location header for redirect'), res);\n  }\n\n  debug('redirect %s -> %s', this.url, url);\n\n  // location\n  url = new URL(url, this.url).href;\n\n  // ensure the response is being consumed\n  // this is required for Node v0.10+\n  res.resume();\n\n  let headers = this.req.getHeaders ? this.req.getHeaders() : this.req._headers;\n\n  const changesOrigin = new URL(url).host !== new URL(this.url).host;\n\n  // implementation of 302 following defacto standard\n  if (res.statusCode === 301 || res.statusCode === 302) {\n    // strip Content-* related fields\n    // in case of POST etc\n    headers = utils.cleanHeader(headers, changesOrigin);\n\n    // force GET\n    this.method = this.method === 'HEAD' ? 'HEAD' : 'GET';\n\n    // clear data\n    this._data = null;\n  }\n\n  // 303 is always GET\n  if (res.statusCode === 303) {\n    // strip Content-* related fields\n    // in case of POST etc\n    headers = utils.cleanHeader(headers, changesOrigin);\n\n    // force method\n    this.method = 'GET';\n\n    // clear data\n    this._data = null;\n  }\n\n  // 307 preserves method\n  // 308 preserves method\n  delete headers.host;\n\n  delete this.req;\n  delete this._formData;\n\n  // remove all add header except User-Agent\n  _initHeaders(this);\n\n  // redirect\n  this.res = res;\n  this._endCalled = false;\n  this.url = url;\n  this.qs = {};\n  this._query.length = 0;\n  this.set(headers);\n  this._emitRedirect();\n  this._redirectList.push(this.url);\n  this.end(this._callback);\n  return this;\n};\n\n/**\n * Set Authorization field value with `user` and `pass`.\n *\n * Examples:\n *\n *   .auth('tobi', 'learnboost')\n *   .auth('tobi:learnboost')\n *   .auth('tobi')\n *   .auth(accessToken, { type: 'bearer' })\n *\n * @param {String} user\n * @param {String} [pass]\n * @param {Object} [options] options with authorization type 'basic' or 'bearer' ('basic' is default)\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.auth = function (user, pass, options) {\n  if (arguments.length === 1) pass = '';\n  if (typeof pass === 'object' && pass !== null) {\n    // pass is optional and can be replaced with options\n    options = pass;\n    pass = '';\n  }\n\n  if (!options) {\n    options = { type: 'basic' };\n  }\n\n  const encoder = (string) => Buffer.from(string).toString('base64');\n\n  return this._auth(user, pass, options, encoder);\n};\n\n/**\n * Set the certificate authority option for https request.\n *\n * @param {Buffer | Array} cert\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.ca = function (cert) {\n  this._ca = cert;\n  return this;\n};\n\n/**\n * Set the client certificate key option for https request.\n *\n * @param {Buffer | String} cert\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.key = function (cert) {\n  this._key = cert;\n  return this;\n};\n\n/**\n * Set the key, certificate, and CA certs of the client in PFX or PKCS12 format.\n *\n * @param {Buffer | String} cert\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.pfx = function (cert) {\n  if (typeof cert === 'object' && !Buffer.isBuffer(cert)) {\n    this._pfx = cert.pfx;\n    this._passphrase = cert.passphrase;\n  } else {\n    this._pfx = cert;\n  }\n\n  return this;\n};\n\n/**\n * Set the client certificate option for https request.\n *\n * @param {Buffer | String} cert\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.cert = function (cert) {\n  this._cert = cert;\n  return this;\n};\n\n/**\n * Do not reject expired or invalid TLS certs.\n * sets `rejectUnauthorized=true`. Be warned that this allows MITM attacks.\n *\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype.disableTLSCerts = function () {\n  this._disableTLSCerts = true;\n  return this;\n};\n\n/**\n * Return an http[s] request.\n *\n * @return {OutgoingMessage}\n * @api private\n */\n\n// eslint-disable-next-line complexity\nRequest.prototype.request = function () {\n  if (this.req) return this.req;\n\n  const options = {};\n\n  try {\n    const query = qs.stringify(this.qs, {\n      indices: false,\n      strictNullHandling: true\n    });\n    if (query) {\n      this.qs = {};\n      this._query.push(query);\n    }\n\n    this._finalizeQueryString();\n  } catch (err) {\n    return this.emit('error', err);\n  }\n\n  let { url: urlString } = this;\n  const retries = this._retries;\n\n  // default to http://\n  if (urlString.indexOf('http') !== 0) urlString = `http://${urlString}`;\n  const url = new URL(urlString);\n  let { protocol } = url;\n  let path = `${url.pathname}${url.search}`;\n\n  // support unix sockets\n  if (/^https?\\+unix:/.test(protocol) === true) {\n    // get the protocol\n    protocol = `${protocol.split('+')[0]}:`;\n\n    // get the socket path\n    options.socketPath = url.hostname.replace(/%2F/g, '/');\n    url.host = '';\n    url.hostname = '';\n  }\n\n  // Override IP address of a hostname\n  if (this._connectOverride) {\n    const { hostname } = url;\n    const match =\n      hostname in this._connectOverride\n        ? this._connectOverride[hostname]\n        : this._connectOverride['*'];\n    if (match) {\n      // backup the real host\n      if (!this._header.host) {\n        this.set('host', url.host);\n      }\n\n      let newHost;\n      let newPort;\n\n      if (typeof match === 'object') {\n        newHost = match.host;\n        newPort = match.port;\n      } else {\n        newHost = match;\n        newPort = url.port;\n      }\n\n      // wrap [ipv6]\n      url.host = /:/.test(newHost) ? `[${newHost}]` : newHost;\n      if (newPort) {\n        url.host += `:${newPort}`;\n        url.port = newPort;\n      }\n\n      url.hostname = newHost;\n    }\n  }\n\n  // options\n  options.method = this.method;\n  options.port = url.port;\n  options.path = path;\n  options.host = utils.normalizeHostname(url.hostname); // ex: [::1] -> ::1\n  options.ca = this._ca;\n  options.key = this._key;\n  options.pfx = this._pfx;\n  options.cert = this._cert;\n  options.passphrase = this._passphrase;\n  options.agent = this._agent;\n  options.lookup = this._lookup;\n  options.rejectUnauthorized =\n    typeof this._disableTLSCerts === 'boolean'\n      ? !this._disableTLSCerts\n      : process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0';\n\n  // Allows request.get('https://1.2.3.4/').set('Host', 'example.com')\n  if (this._header.host) {\n    options.servername = this._header.host.replace(/:\\d+$/, '');\n  }\n\n  if (\n    this._trustLocalhost &&\n    /^(?:localhost|127\\.0\\.0\\.\\d+|(0*:)+:0*1)$/.test(url.hostname)\n  ) {\n    options.rejectUnauthorized = false;\n  }\n\n  // initiate request\n  const module_ = this._enableHttp2\n    ? exports.protocols['http2:'].setProtocol(protocol)\n    : exports.protocols[protocol];\n\n  // request\n  this.req = module_.request(options);\n  const { req } = this;\n\n  // set tcp no delay\n  req.setNoDelay(true);\n\n  if (options.method !== 'HEAD') {\n    req.setHeader('Accept-Encoding', 'gzip, deflate');\n  }\n\n  this.protocol = protocol;\n  this.host = url.host;\n\n  // expose events\n  req.once('drain', () => {\n    this.emit('drain');\n  });\n\n  req.on('error', (error) => {\n    // flag abortion here for out timeouts\n    // because node will emit a faux-error \"socket hang up\"\n    // when request is aborted before a connection is made\n    if (this._aborted) return;\n    // if not the same, we are in the **old** (cancelled) request,\n    // so need to continue (same as for above)\n    if (this._retries !== retries) return;\n    // if we've received a response then we don't want to let\n    // an error in the request blow up the response\n    if (this.response) return;\n    this.callback(error);\n  });\n\n  // auth\n  if (url.username || url.password) {\n    this.auth(url.username, url.password);\n  }\n\n  if (this.username && this.password) {\n    this.auth(this.username, this.password);\n  }\n\n  for (const key in this.header) {\n    if (hasOwn(this.header, key)) req.setHeader(key, this.header[key]);\n  }\n\n  // add cookies\n  if (this.cookies) {\n    if (hasOwn(this._header, 'cookie')) {\n      // merge\n      const temporaryJar = new CookieJar.CookieJar();\n      temporaryJar.setCookies(this._header.cookie.split('; '));\n      temporaryJar.setCookies(this.cookies.split('; '));\n      req.setHeader(\n        'Cookie',\n        temporaryJar.getCookies(CookieJar.CookieAccessInfo.All).toValueString()\n      );\n    } else {\n      req.setHeader('Cookie', this.cookies);\n    }\n  }\n\n  return req;\n};\n\n/**\n * Invoke the callback with `err` and `res`\n * and handle arity check.\n *\n * @param {Error} err\n * @param {Response} res\n * @api private\n */\n\nRequest.prototype.callback = function (error, res) {\n  if (this._shouldRetry(error, res)) {\n    return this._retry();\n  }\n\n  // Avoid the error which is emitted from 'socket hang up' to cause the fn undefined error on JS runtime.\n  const fn = this._callback || noop;\n  this.clearTimeout();\n  if (this.called) return console.warn('superagent: double callback bug');\n  this.called = true;\n\n  if (!error) {\n    try {\n      if (!this._isResponseOK(res)) {\n        let message = 'Unsuccessful HTTP response';\n        if (res) {\n          message = http.STATUS_CODES[res.status] || message;\n        }\n\n        error = new Error(message);\n        error.status = res ? res.status : undefined;\n      }\n    } catch (err) {\n      error = err;\n      error.status = error.status || (res ? res.status : undefined);\n    }\n  }\n\n  // It's important that the callback is called outside try/catch\n  // to avoid double callback\n  if (!error) {\n    return fn(null, res);\n  }\n\n  error.response = res;\n  if (this._maxRetries) error.retries = this._retries - 1;\n\n  // only emit error event if there is a listener\n  // otherwise we assume the callback to `.end()` will get the error\n  if (error && this.listeners('error').length > 0) {\n    this.emit('error', error);\n  }\n\n  fn(error, res);\n};\n\n/**\n * Check if `obj` is a host object,\n *\n * @param {Object} obj host object\n * @return {Boolean} is a host object\n * @api private\n */\nRequest.prototype._isHost = function (object) {\n  return (\n    Buffer.isBuffer(object) ||\n    object instanceof Stream ||\n    object instanceof FormData\n  );\n};\n\n/**\n * Initiate request, invoking callback `fn(err, res)`\n * with an instanceof `Response`.\n *\n * @param {Function} fn\n * @return {Request} for chaining\n * @api public\n */\n\nRequest.prototype._emitResponse = function (body, files) {\n  const response = new Response(this);\n  this.response = response;\n  response.redirects = this._redirectList;\n  if (undefined !== body) {\n    response.body = body;\n  }\n\n  response.files = files;\n  if (this._endCalled) {\n    response.pipe = function () {\n      throw new Error(\n        \"end() has already been called, so it's too late to start piping\"\n      );\n    };\n  }\n\n  this.emit('response', response);\n  return response;\n};\n\n/**\n * Emit `redirect` event, passing an instanceof `Response`.\n *\n * @api private\n */\n\nRequest.prototype._emitRedirect = function () {\n  const response = new Response(this);\n  response.redirects = this._redirectList;\n  this.emit('redirect', response);\n};\n\nRequest.prototype.end = function (fn) {\n  this.request();\n  debug('%s %s', this.method, this.url);\n\n  if (this._endCalled) {\n    throw new Error(\n      '.end() was called twice. This is not supported in superagent'\n    );\n  }\n\n  this._endCalled = true;\n\n  // store callback\n  this._callback = fn || noop;\n\n  this._end();\n};\n\nRequest.prototype._end = function () {\n  if (this._aborted)\n    return this.callback(\n      new Error('The request has been aborted even before .end() was called')\n    );\n\n  let data = this._data;\n  const { req } = this;\n  const { method } = this;\n\n  this._setTimeouts();\n\n  // body\n  if (method !== 'HEAD' && !req._headerSent) {\n    // serialize stuff\n    if (typeof data !== 'string') {\n      let contentType = req.getHeader('Content-Type');\n      // Parse out just the content type from the header (ignore the charset)\n      if (contentType) contentType = contentType.split(';')[0];\n      let serialize = this._serializer || exports.serialize[contentType];\n      if (!serialize && isJSON(contentType)) {\n        serialize = exports.serialize['application/json'];\n      }\n\n      if (serialize) data = serialize(data);\n    }\n\n    // content-length\n    if (data && !req.getHeader('Content-Length')) {\n      req.setHeader(\n        'Content-Length',\n        Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)\n      );\n    }\n  }\n\n  // response\n  // eslint-disable-next-line complexity\n  req.once('response', (res) => {\n    debug('%s %s -> %s', this.method, this.url, res.statusCode);\n\n    if (this._responseTimeoutTimer) {\n      clearTimeout(this._responseTimeoutTimer);\n    }\n\n    if (this.piped) {\n      return;\n    }\n\n    const max = this._maxRedirects;\n    const mime = utils.type(res.headers['content-type'] || '') || 'text/plain';\n    let type = mime.split('/')[0];\n    if (type) type = type.toLowerCase().trim();\n    const multipart = type === 'multipart';\n    const redirect = isRedirect(res.statusCode);\n    const responseType = this._responseType;\n\n    this.res = res;\n\n    // redirect\n    if (redirect && this._redirects++ !== max) {\n      return this._redirect(res);\n    }\n\n    if (this.method === 'HEAD') {\n      this.emit('end');\n      this.callback(null, this._emitResponse());\n      return;\n    }\n\n    // zlib support\n    if (this._shouldDecompress(res)) {\n      decompress(req, res);\n    }\n\n    let buffer = this._buffer;\n    if (buffer === undefined && mime in exports.buffer) {\n      buffer = Boolean(exports.buffer[mime]);\n    }\n\n    let parser = this._parser;\n    if (undefined === buffer && parser) {\n      console.warn(\n        \"A custom superagent parser has been set, but buffering strategy for the parser hasn't been configured. Call `req.buffer(true or false)` or set `superagent.buffer[mime] = true or false`\"\n      );\n      buffer = true;\n    }\n\n    if (!parser) {\n      if (responseType) {\n        parser = exports.parse.image; // It's actually a generic Buffer\n        buffer = true;\n      } else if (multipart) {\n        const form = formidable.formidable();\n        parser = (res, callback) => {\n          // Create a PassThrough stream that acts as a proper HTTP request\n          const bridgeStream = new Stream.PassThrough();\n\n          // Add HTTP request properties from the current request context\n          bridgeStream.method = this.method || 'POST';\n          bridgeStream.url = this.url || '/';\n          bridgeStream.httpVersion = res.httpVersion || '1.1';\n          bridgeStream.headers = res.headers || {};\n          bridgeStream.socket = res.socket || { readable: true };\n\n          // Pipe the response data through the bridge stream\n          res.pipe(bridgeStream);\n\n          form.parse(bridgeStream, (err, fields, files) => {\n            if (err) return callback(err);\n\n            // Formidable v3 always returns arrays, but SuperAgent expects single values\n            // Flatten single-item arrays to maintain backward compatibility\n            const flattenedFields = {};\n            if (fields) {\n              for (const key in fields) {\n                const value = fields[key];\n                flattenedFields[key] = Array.isArray(value) && value.length === 1 ? value[0] : value;\n              }\n            }\n\n            const flattenedFiles = {};\n            if (files) {\n              for (const key in files) {\n                const value = files[key];\n                flattenedFiles[key] = Array.isArray(value) && value.length === 1 ? value[0] : value;\n              }\n            }\n\n            // Return flattened fields as the object parameter to match SuperAgent's expected format\n            callback(null, flattenedFields, flattenedFiles);\n          });\n        };\n        buffer = true;\n      } else if (isBinary(mime)) {\n        parser = exports.parse.image;\n        buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent\n      } else if (exports.parse[mime]) {\n        parser = exports.parse[mime];\n      } else if (type === 'text') {\n        parser = exports.parse.text;\n        buffer = buffer !== false;\n        // everyone wants their own white-labeled json\n      } else if (isJSON(mime)) {\n        parser = exports.parse['application/json'];\n        buffer = buffer !== false;\n      } else if (buffer) {\n        parser = exports.parse.text;\n      } else if (undefined === buffer) {\n        parser = exports.parse.image; // It's actually a generic Buffer\n        buffer = true;\n      }\n    }\n\n    // by default only buffer text/*, json and messed up thing from hell\n    if ((undefined === buffer && isText(mime)) || isJSON(mime)) {\n      buffer = true;\n    }\n\n    this._resBuffered = buffer;\n    let parserHandlesEnd = false;\n    if (buffer) {\n      // Protectiona against zip bombs and other nuisance\n      let responseBytesLeft = this._maxResponseSize || 200000000;\n      res.on('data', (buf) => {\n        responseBytesLeft -= buf.byteLength || buf.length > 0 ? buf.length : 0;\n        if (responseBytesLeft < 0) {\n          // This will propagate through error event\n          const error = new Error('Maximum response size reached');\n          error.code = 'ETOOLARGE';\n          // Parsers aren't required to observe error event,\n          // so would incorrectly report success\n          parserHandlesEnd = false;\n          // Will not emit error event\n          res.destroy(error);\n          // so we do callback now\n          this.callback(error, null);\n        }\n      });\n    }\n\n    if (parser) {\n      try {\n        // Unbuffered parsers are supposed to emit response early,\n        // which is weird BTW, because response.body won't be there.\n        parserHandlesEnd = buffer;\n\n        parser(res, (error, object, files) => {\n          if (this.timedout) {\n            // Timeout has already handled all callbacks\n            return;\n          }\n\n          // Intentional (non-timeout) abort is supposed to preserve partial response,\n          // even if it doesn't parse.\n          if (error && !this._aborted) {\n            return this.callback(error);\n          }\n\n          if (parserHandlesEnd) {\n            this.emit('end');\n            this.callback(null, this._emitResponse(object, files));\n          }\n        });\n      } catch (err) {\n        this.callback(err);\n        return;\n      }\n    }\n\n    this.res = res;\n\n    // unbuffered\n    if (!buffer) {\n      debug('unbuffered %s %s', this.method, this.url);\n      this.callback(null, this._emitResponse());\n      if (multipart) return; // allow multipart to handle end event\n      res.once('end', () => {\n        debug('end %s %s', this.method, this.url);\n        this.emit('end');\n      });\n      return;\n    }\n\n    // terminating events\n    res.once('error', (error) => {\n      parserHandlesEnd = false;\n      this.callback(error, null);\n    });\n    if (!parserHandlesEnd)\n      res.once('end', () => {\n        debug('end %s %s', this.method, this.url);\n        // TODO: unless buffering emit earlier to stream\n        this.emit('end');\n        this.callback(null, this._emitResponse());\n      });\n  });\n\n  this.emit('request', this);\n\n  const getProgressMonitor = () => {\n    const lengthComputable = true;\n    const total = req.getHeader('Content-Length');\n    let loaded = 0;\n\n    const progress = new Stream.Transform();\n    progress._transform = (chunk, encoding, callback) => {\n      loaded += chunk.length;\n      this.emit('progress', {\n        direction: 'upload',\n        lengthComputable,\n        loaded,\n        total\n      });\n      callback(null, chunk);\n    };\n\n    return progress;\n  };\n\n  const bufferToChunks = (buffer) => {\n    const chunkSize = 16 * 1024; // default highWaterMark value\n    const chunking = new Stream.Readable();\n    const totalLength = buffer.length;\n    const remainder = totalLength % chunkSize;\n    const cutoff = totalLength - remainder;\n\n    for (let i = 0; i < cutoff; i += chunkSize) {\n      const chunk = buffer.slice(i, i + chunkSize);\n      chunking.push(chunk);\n    }\n\n    if (remainder > 0) {\n      const remainderBuffer = buffer.slice(-remainder);\n      chunking.push(remainderBuffer);\n    }\n\n    chunking.push(null); // no more data\n\n    return chunking;\n  };\n\n  // if a FormData instance got created, then we send that as the request body\n  const formData = this._formData;\n  if (formData) {\n    // set headers\n    const headers = formData.getHeaders();\n    for (const i in headers) {\n      if (hasOwn(headers, i)) {\n        debug('setting FormData header: \"%s: %s\"', i, headers[i]);\n        req.setHeader(i, headers[i]);\n      }\n    }\n\n    // attempt to get \"Content-Length\" header\n    formData.getLength((error, length) => {\n      // TODO: Add chunked encoding when no length (if err)\n      if (error) debug('formData.getLength had error', error, length);\n\n      debug('got FormData Content-Length: %s', length);\n      if (typeof length === 'number') {\n        req.setHeader('Content-Length', length);\n      }\n\n      formData.pipe(getProgressMonitor()).pipe(req);\n    });\n  } else if (Buffer.isBuffer(data)) {\n    bufferToChunks(data).pipe(getProgressMonitor()).pipe(req);\n  } else {\n    req.end(data);\n  }\n};\n\n// Check whether response has a non-0-sized gzip-encoded body\nRequest.prototype._shouldDecompress = (res) => {\n  return hasNonEmptyResponseContent(res) && (isGzipOrDeflateEncoding(res) || isBrotliEncoding(res));\n};\n\n\n/**\n * Overrides DNS for selected hostnames. Takes object mapping hostnames to IP addresses.\n *\n * When making a request to a URL with a hostname exactly matching a key in the object,\n * use the given IP address to connect, instead of using DNS to resolve the hostname.\n *\n * A special host `*` matches every hostname (keep redirects in mind!)\n *\n *      request.connect({\n *        'test.example.com': '127.0.0.1',\n *        'ipv6.example.com': '::1',\n *      })\n */\nRequest.prototype.connect = function (connectOverride) {\n  if (typeof connectOverride === 'string') {\n    this._connectOverride = { '*': connectOverride };\n  } else if (typeof connectOverride === 'object') {\n    this._connectOverride = connectOverride;\n  } else {\n    this._connectOverride = undefined;\n  }\n\n  return this;\n};\n\nRequest.prototype.trustLocalhost = function (toggle) {\n  this._trustLocalhost = toggle === undefined ? true : toggle;\n  return this;\n};\n\n// generate HTTP verb methods\nif (!methods.includes('del')) {\n  // create a copy so we don't cause conflicts with\n  // other packages using the methods package and\n  // npm 3.x\n  methods = [...methods];\n  methods.push('del');\n}\n\nfor (let method of methods) {\n  const name = method;\n  method = method === 'del' ? 'delete' : method;\n\n  method = method.toUpperCase();\n  request[name] = (url, data, fn) => {\n    const request_ = request(method, url);\n    if (typeof data === 'function') {\n      fn = data;\n      data = null;\n    }\n\n    if (data) {\n      if (method === 'GET' || method === 'HEAD') {\n        request_.query(data);\n      } else {\n        request_.send(data);\n      }\n    }\n\n    if (fn) request_.end(fn);\n    return request_;\n  };\n}\n\n/**\n * Check if `mime` is text and should be buffered.\n *\n * @param {String} mime\n * @return {Boolean}\n * @api public\n */\n\nfunction isText(mime) {\n  const parts = mime.split('/');\n  let type = parts[0];\n  if (type) type = type.toLowerCase().trim();\n  let subtype = parts[1];\n  if (subtype) subtype = subtype.toLowerCase().trim();\n\n  return type === 'text' || subtype === 'x-www-form-urlencoded';\n}\n\n// This is not a catchall, but a start. It might be useful\n// in the long run to have file that includes all binary\n// content types from https://www.iana.org/assignments/media-types/media-types.xhtml\nfunction isBinary(mime) {\n  let [registry, name] = mime.split('/');\n  if (registry) registry = registry.toLowerCase().trim();\n  if (name) name = name.toLowerCase().trim();\n  return (\n    ['audio', 'font', 'image', 'video'].includes(registry) ||\n    ['gz', 'gzip'].includes(name)\n  );\n}\n\n/**\n * Check if `mime` is json or has +json structured syntax suffix.\n *\n * @param {String} mime\n * @return {Boolean}\n * @api private\n */\n\nfunction isJSON(mime) {\n  // should match /json or +json\n  // but not /json-seq\n  return /[/+]json($|[^-\\w])/i.test(mime);\n}\n\n/**\n * Check if we should follow the redirect `code`.\n *\n * @param {Number} code\n * @return {Boolean}\n * @api private\n */\n\nfunction isRedirect(code) {\n  return [301, 302, 303, 305, 307, 308].includes(code);\n}\n\nfunction hasNonEmptyResponseContent(res) {\n  if (res.statusCode === 204 || res.statusCode === 304) {\n    // These aren't supposed to have any body\n    return false;\n  }\n\n  // header content is a string, and distinction between 0 and no information is crucial\n  if (res.headers['content-length'] === '0') {\n    // We know that the body is empty (unfortunately, this check does not cover chunked encoding)\n    return false;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/node/parsers/image.js",
    "content": "module.exports = (res, fn) => {\n  const data = []; // Binary data needs binary storage\n\n  res.on('data', (chunk) => {\n    data.push(chunk);\n  });\n  res.on('end', () => {\n    fn(null, Buffer.concat(data));\n  });\n};\n"
  },
  {
    "path": "src/node/parsers/index.js",
    "content": "exports['application/x-www-form-urlencoded'] = require('./urlencoded');\nexports['application/json'] = require('./json');\nexports.text = require('./text');\n\nexports['application/json-seq'] = exports.text;\n\nconst binary = require('./image');\n\nexports['application/octet-stream'] = binary;\nexports['application/pdf'] = binary;\nexports.image = binary;\n"
  },
  {
    "path": "src/node/parsers/json.js",
    "content": "module.exports = function (res, fn) {\n  res.text = '';\n  res.setEncoding('utf8');\n  res.on('data', (chunk) => {\n    res.text += chunk;\n  });\n  res.on('end', () => {\n    let body;\n    let error;\n    try {\n      body = res.text && JSON.parse(res.text);\n    } catch (err) {\n      error = err;\n      // issue #675: return the raw response if the response parsing fails\n      error.rawResponse = res.text || null;\n      // issue #876: return the http status code if the response parsing fails\n      error.statusCode = res.statusCode;\n    } finally {\n      fn(error, body);\n    }\n  });\n};\n"
  },
  {
    "path": "src/node/parsers/text.js",
    "content": "module.exports = (res, fn) => {\n  res.text = '';\n  res.setEncoding('utf8');\n  res.on('data', (chunk) => {\n    res.text += chunk;\n  });\n  res.on('end', fn);\n};\n"
  },
  {
    "path": "src/node/parsers/urlencoded.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst qs = require('qs');\n\nmodule.exports = (res, fn) => {\n  res.text = '';\n  res.setEncoding('ascii');\n  res.on('data', (chunk) => {\n    res.text += chunk;\n  });\n  res.on('end', () => {\n    try {\n      fn(null, qs.parse(res.text));\n    } catch (err) {\n      fn(err);\n    }\n  });\n};\n"
  },
  {
    "path": "src/node/response.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst util = require('util');\nconst Stream = require('stream');\nconst ResponseBase = require('../response-base');\nconst { mixin } = require('../utils');\n\n/**\n * Expose `Response`.\n */\n\nmodule.exports = Response;\n\n/**\n * Initialize a new `Response` with the given `xhr`.\n *\n *  - set flags (.ok, .error, etc)\n *  - parse header\n *\n * @param {Request} req\n * @param {Object} options\n * @constructor\n * @extends {Stream}\n * @implements {ReadableStream}\n * @api private\n */\n\nfunction Response(request) {\n  Stream.call(this);\n  this.res = request.res;\n  const { res } = this;\n  this.request = request;\n  this.req = request.req;\n  this.text = res.text;\n  this.files = res.files || {};\n  this.buffered = request._resBuffered;\n  this.headers = res.headers;\n  this.header = this.headers;\n  this._setStatusProperties(res.statusCode);\n  this._setHeaderProperties(this.header);\n  this.setEncoding = res.setEncoding.bind(res);\n  res.on('data', this.emit.bind(this, 'data'));\n  res.on('end', this.emit.bind(this, 'end'));\n  res.on('close', this.emit.bind(this, 'close'));\n  res.on('error', this.emit.bind(this, 'error'));\n}\n\n// Lazy access res.body.\n// https://github.com/nodejs/node/pull/39520#issuecomment-889697136\nObject.defineProperty(Response.prototype, 'body', {\n  get() {\n    return this._body !== undefined\n      ? this._body\n      : this.res.body !== undefined\n      ? this.res.body\n      : {};\n  },\n  set(value) {\n    this._body = value;\n  }\n});\n\n/**\n * Inherit from `Stream`.\n */\n\nutil.inherits(Response, Stream);\n\nmixin(Response.prototype, ResponseBase.prototype);\n\n/**\n * Implements methods of a `ReadableStream`\n */\n\nResponse.prototype.destroy = function (error) {\n  this.res.destroy(error);\n};\n\n/**\n * Pause.\n */\n\nResponse.prototype.pause = function () {\n  this.res.pause();\n};\n\n/**\n * Resume.\n */\n\nResponse.prototype.resume = function () {\n  this.res.resume();\n};\n\n/**\n * Return an `Error` representative of this response.\n *\n * @return {Error}\n * @api public\n */\n\nResponse.prototype.toError = function () {\n  const { req } = this;\n  const { method } = req;\n  const { path } = req;\n\n  const message = `cannot ${method} ${path} (${this.status})`;\n  const error = new Error(message);\n  error.status = this.status;\n  error.text = this.text;\n  error.method = method;\n  error.path = path;\n\n  return error;\n};\n\nResponse.prototype.setStatusProperties = function (status) {\n  console.warn('In superagent 2.x setStatusProperties is a private method');\n  return this._setStatusProperties(status);\n};\n\n/**\n * To json.\n *\n * @return {Object}\n * @api public\n */\n\nResponse.prototype.toJSON = function () {\n  return {\n    req: this.request.toJSON(),\n    header: this.header,\n    status: this.status,\n    text: this.text\n  };\n};\n"
  },
  {
    "path": "src/node/unzip.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst { StringDecoder } = require('string_decoder');\nconst Stream = require('stream');\nconst { chooseDecompresser } = require('./decompress');\n\n/**\n * Buffers response data events and re-emits when they're decompressed.\n *\n * @param {Request} req\n * @param {Response} res\n * @api private\n */\n\nexports.decompress = (request, res) => {\n  let decompresser = chooseDecompresser(res);\n\n  const stream = new Stream();\n  let decoder;\n\n  // make node responseOnEnd() happy\n  stream.req = request;\n\n  decompresser.on('error', (error) => {\n    if (error && error.code === 'Z_BUF_ERROR') {\n      // unexpected end of file is ignored by browsers and curl\n      stream.emit('end');\n      return;\n    }\n\n    stream.emit('error', error);\n  });\n\n  // pipe to unzip\n  res.pipe(decompresser);\n\n  // override `setEncoding` to capture encoding\n  res.setEncoding = (type) => {\n    decoder = new StringDecoder(type);\n  };\n\n  // decode upon decompressing with captured encoding\n  decompresser.on('data', (buf) => {\n    if (decoder) {\n      const string_ = decoder.write(buf);\n      if (string_.length > 0) stream.emit('data', string_);\n    } else {\n      stream.emit('data', buf);\n    }\n  });\n\n  decompresser.on('end', () => {\n    stream.emit('end');\n  });\n\n  // override `on` to capture data listeners\n  const _on = res.on;\n  res.on = function (type, fn) {\n    if (type === 'data' || type === 'end') {\n      stream.on(type, fn.bind(res));\n    } else if (type === 'error') {\n      stream.on(type, fn.bind(res));\n      _on.call(res, type, fn);\n    } else {\n      _on.call(res, type, fn);\n    }\n\n    return this;\n  };\n};\n"
  },
  {
    "path": "src/request-base.js",
    "content": "/**\n * Module of mixed-in functions shared between node and client code\n */\nconst { isObject, hasOwn } = require('./utils');\n\n/**\n * Expose `RequestBase`.\n */\n\nmodule.exports = RequestBase;\n\n/**\n * Initialize a new `RequestBase`.\n *\n * @api public\n */\n\nfunction RequestBase() {}\n\n/**\n * Clear previous timeout.\n *\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.clearTimeout = function () {\n  clearTimeout(this._timer);\n  clearTimeout(this._responseTimeoutTimer);\n  clearTimeout(this._uploadTimeoutTimer);\n  delete this._timer;\n  delete this._responseTimeoutTimer;\n  delete this._uploadTimeoutTimer;\n  return this;\n};\n\n/**\n * Override default response body parser\n *\n * This function will be called to convert incoming data into request.body\n *\n * @param {Function}\n * @api public\n */\n\nRequestBase.prototype.parse = function (fn) {\n  this._parser = fn;\n  return this;\n};\n\n/**\n * Set format of binary response body.\n * In browser valid formats are 'blob' and 'arraybuffer',\n * which return Blob and ArrayBuffer, respectively.\n *\n * In Node all values result in Buffer.\n *\n * Examples:\n *\n *      req.get('/')\n *        .responseType('blob')\n *        .end(callback);\n *\n * @param {String} val\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.responseType = function (value) {\n  this._responseType = value;\n  return this;\n};\n\n/**\n * Override default request body serializer\n *\n * This function will be called to convert data set via .send or .attach into payload to send\n *\n * @param {Function}\n * @api public\n */\n\nRequestBase.prototype.serialize = function (fn) {\n  this._serializer = fn;\n  return this;\n};\n\n/**\n * Set timeouts.\n *\n * - response timeout is time between sending request and receiving the first byte of the response. Includes DNS and connection time.\n * - deadline is the time from start of the request to receiving response body in full. If the deadline is too short large files may not load at all on slow connections.\n * - upload is the time  since last bit of data was sent or received. This timeout works only if deadline timeout is off\n *\n * Value of 0 or false means no timeout.\n *\n * @param {Number|Object} ms or {response, deadline}\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.timeout = function (options) {\n  if (!options || typeof options !== 'object') {\n    this._timeout = options;\n    this._responseTimeout = 0;\n    this._uploadTimeout = 0;\n    return this;\n  }\n\n  for (const option in options) {\n    if (hasOwn(options, option)) {\n      switch (option) {\n        case 'deadline':\n          this._timeout = options.deadline;\n          break;\n        case 'response':\n          this._responseTimeout = options.response;\n          break;\n        case 'upload':\n          this._uploadTimeout = options.upload;\n          break;\n        default:\n          console.warn('Unknown timeout option', option);\n      }\n    }\n  }\n\n  return this;\n};\n\n/**\n * Set number of retry attempts on error.\n *\n * Failed requests will be retried 'count' times if timeout or err.code >= 500.\n *\n * @param {Number} count\n * @param {Function} [fn]\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.retry = function (count, fn) {\n  // Default to 1 if no count passed or true\n  if (arguments.length === 0 || count === true) count = 1;\n  if (count <= 0) count = 0;\n  this._maxRetries = count;\n  this._retries = 0;\n  this._retryCallback = fn;\n  return this;\n};\n\n//\n// NOTE: we do not include ESOCKETTIMEDOUT because that is from `request` package\n//       <https://github.com/sindresorhus/got/pull/537>\n//\n// NOTE: we do not include EADDRINFO because it was removed from libuv in 2014\n//       <https://github.com/libuv/libuv/commit/02e1ebd40b807be5af46343ea873331b2ee4e9c1>\n//       <https://github.com/request/request/search?q=ESOCKETTIMEDOUT&unscoped_q=ESOCKETTIMEDOUT>\n//\n//\n// TODO: expose these as configurable defaults\n//\nconst ERROR_CODES = new Set([\n  'ETIMEDOUT',\n  'ECONNRESET',\n  'EADDRINUSE',\n  'ECONNREFUSED',\n  'EPIPE',\n  'ENOTFOUND',\n  'ENETUNREACH',\n  'EAI_AGAIN'\n]);\n\nconst STATUS_CODES = new Set([\n  408, 413, 429, 500, 502, 503, 504, 521, 522, 524\n]);\n\n// TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST)\n// const METHODS = new Set(['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE']);\n\n/**\n * Determine if a request should be retried.\n * (Inspired by https://github.com/sindresorhus/got#retry)\n *\n * @param {Error} err an error\n * @param {Response} [res] response\n * @returns {Boolean} if segment should be retried\n */\nRequestBase.prototype._shouldRetry = function (error, res) {\n  if (!this._maxRetries || this._retries++ >= this._maxRetries) {\n    return false;\n  }\n\n  if (this._retryCallback) {\n    try {\n      const override = this._retryCallback(error, res);\n      if (override === true) return true;\n      if (override === false) return false;\n      // undefined falls back to defaults\n    } catch (err) {\n      console.error(err);\n    }\n  }\n\n  // TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST)\n  /*\n  if (\n    this.req &&\n    this.req.method &&\n    !METHODS.has(this.req.method.toUpperCase())\n  )\n    return false;\n  */\n  if (res && res.status && STATUS_CODES.has(res.status)) return true;\n  if (error) {\n    if (error.code && ERROR_CODES.has(error.code)) return true;\n    // Superagent timeout\n    if (error.timeout && error.code === 'ECONNABORTED') return true;\n    if (error.crossDomain) return true;\n  }\n\n  return false;\n};\n\n/**\n * Retry request\n *\n * @return {Request} for chaining\n * @api private\n */\n\nRequestBase.prototype._retry = function () {\n  this.clearTimeout();\n\n  // node\n  if (this.req) {\n    this.req = null;\n    this.req = this.request();\n  }\n\n  this._aborted = false;\n  this.timedout = false;\n  this.timedoutError = null;\n\n  return this._end();\n};\n\n/**\n * Promise support\n *\n * @param {Function} resolve\n * @param {Function} [reject]\n * @return {Request}\n */\n\nRequestBase.prototype.then = function (resolve, reject) {\n  if (!this._fullfilledPromise) {\n    const self = this;\n    if (this._endCalled) {\n      console.warn(\n        'Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises'\n      );\n    }\n\n    this._fullfilledPromise = new Promise((resolve, reject) => {\n      self.on('abort', () => {\n        if (this._maxRetries && this._maxRetries > this._retries) {\n          return;\n        }\n\n        if (this.timedout && this.timedoutError) {\n          reject(this.timedoutError);\n          return;\n        }\n\n        const error = new Error('Aborted');\n        error.code = 'ABORTED';\n        error.status = this.status;\n        error.method = this.method;\n        error.url = this.url;\n        reject(error);\n      });\n      self.end((error, res) => {\n        if (error) reject(error);\n        else resolve(res);\n      });\n    });\n  }\n\n  return this._fullfilledPromise.then(resolve, reject);\n};\n\nRequestBase.prototype.catch = function (callback) {\n  return this.then(undefined, callback);\n};\n\n/**\n * Allow for extension\n */\n\nRequestBase.prototype.use = function (fn) {\n  fn(this);\n  return this;\n};\n\nRequestBase.prototype.ok = function (callback) {\n  if (typeof callback !== 'function') throw new Error('Callback required');\n  this._okCallback = callback;\n  return this;\n};\n\nRequestBase.prototype._isResponseOK = function (res) {\n  if (!res) {\n    return false;\n  }\n\n  if (this._okCallback) {\n    return this._okCallback(res);\n  }\n\n  return res.status >= 200 && res.status < 300;\n};\n\n/**\n * Get request header `field`.\n * Case-insensitive.\n *\n * @param {String} field\n * @return {String}\n * @api public\n */\n\nRequestBase.prototype.get = function (field) {\n  return this._header[field.toLowerCase()];\n};\n\n/**\n * Get case-insensitive header `field` value.\n * This is a deprecated internal API. Use `.get(field)` instead.\n *\n * (getHeader is no longer used internally by the superagent code base)\n *\n * @param {String} field\n * @return {String}\n * @api private\n * @deprecated\n */\n\nRequestBase.prototype.getHeader = RequestBase.prototype.get;\n\n/**\n * Set header `field` to `val`, or multiple fields with one object.\n * Case-insensitive.\n *\n * Examples:\n *\n *      req.get('/')\n *        .set('Accept', 'application/json')\n *        .set('X-API-Key', 'foobar')\n *        .end(callback);\n *\n *      req.get('/')\n *        .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })\n *        .end(callback);\n *\n * @param {String|Object} field\n * @param {String} val\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.set = function (field, value) {\n  if (isObject(field)) {\n    for (const key in field) {\n      if (hasOwn(field, key)) this.set(key, field[key]);\n    }\n\n    return this;\n  }\n\n  this._header[field.toLowerCase()] = value;\n  this.header[field] = value;\n  return this;\n};\n\n/**\n * Remove header `field`.\n * Case-insensitive.\n *\n * Example:\n *\n *      req.get('/')\n *        .unset('User-Agent')\n *        .end(callback);\n *\n * @param {String} field field name\n */\nRequestBase.prototype.unset = function (field) {\n  delete this._header[field.toLowerCase()];\n  delete this.header[field];\n  return this;\n};\n\n/**\n * Write the field `name` and `val`, or multiple fields with one object\n * for \"multipart/form-data\" request bodies.\n *\n * ``` js\n * request.post('/upload')\n *   .field('foo', 'bar')\n *   .end(callback);\n *\n * request.post('/upload')\n *   .field({ foo: 'bar', baz: 'qux' })\n *   .end(callback);\n * ```\n *\n * @param {String|Object} name name of field\n * @param {String|Blob|File|Buffer|fs.ReadStream} val value of field\n * @param {String} options extra options, e.g. 'blob'\n * @return {Request} for chaining\n * @api public\n */\nRequestBase.prototype.field = function (name, value, options) {\n  // name should be either a string or an object.\n  if (name === null || undefined === name) {\n    throw new Error('.field(name, val) name can not be empty');\n  }\n\n  if (this._data) {\n    throw new Error(\n      \".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()\"\n    );\n  }\n\n  if (isObject(name)) {\n    for (const key in name) {\n      if (hasOwn(name, key)) this.field(key, name[key]);\n    }\n\n    return this;\n  }\n\n  if (Array.isArray(value)) {\n    for (const i in value) {\n      if (hasOwn(value, i)) this.field(name, value[i]);\n    }\n\n    return this;\n  }\n\n  // val should be defined now\n  if (value === null || undefined === value) {\n    throw new Error('.field(name, val) val can not be empty');\n  }\n\n  if (typeof value === 'boolean') {\n    value = String(value);\n  }\n\n  // fix https://github.com/ladjs/superagent/issues/1680\n  if (options) this._getFormData().append(name, value, options);\n  else this._getFormData().append(name, value);\n\n  return this;\n};\n\n/**\n * Abort the request, and clear potential timeout.\n *\n * @return {Request} request\n * @api public\n */\nRequestBase.prototype.abort = function () {\n  if (this._aborted) {\n    return this;\n  }\n\n  this._aborted = true;\n  if (this.xhr) this.xhr.abort(); // browser\n  if (this.req) {\n    this.req.abort(); // node\n  }\n\n  this.clearTimeout();\n  this.emit('abort');\n  return this;\n};\n\nRequestBase.prototype._auth = function (user, pass, options, base64Encoder) {\n  switch (options.type) {\n    case 'basic':\n      this.set('Authorization', `Basic ${base64Encoder(`${user}:${pass}`)}`);\n      break;\n\n    case 'auto':\n      this.username = user;\n      this.password = pass;\n      break;\n\n    case 'bearer': // usage would be .auth(accessToken, { type: 'bearer' })\n      this.set('Authorization', `Bearer ${user}`);\n      break;\n    default:\n      break;\n  }\n\n  return this;\n};\n\n/**\n * Enable transmission of cookies with x-domain requests.\n *\n * Note that for this to work the origin must not be\n * using \"Access-Control-Allow-Origin\" with a wildcard,\n * and also must set \"Access-Control-Allow-Credentials\"\n * to \"true\".\n * @param {Boolean} [on=true] - Set 'withCredentials' state\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.withCredentials = function (on) {\n  // This is browser-only functionality. Node side is no-op.\n  if (on === undefined) on = true;\n  this._withCredentials = on;\n  return this;\n};\n\n/**\n * Set the max redirects to `n`. Does nothing in browser XHR implementation.\n *\n * @param {Number} n\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.redirects = function (n) {\n  this._maxRedirects = n;\n  return this;\n};\n\n/**\n * Maximum size of buffered response body, in bytes. Counts uncompressed size.\n * Default 200MB.\n *\n * @param {Number} n number of bytes\n * @return {Request} for chaining\n */\nRequestBase.prototype.maxResponseSize = function (n) {\n  if (typeof n !== 'number') {\n    throw new TypeError('Invalid argument');\n  }\n\n  this._maxResponseSize = n;\n  return this;\n};\n\n/**\n * Convert to a plain javascript object (not JSON string) of scalar properties.\n * Note as this method is designed to return a useful non-this value,\n * it cannot be chained.\n *\n * @return {Object} describing method, url, and data of this request\n * @api public\n */\n\nRequestBase.prototype.toJSON = function () {\n  return {\n    method: this.method,\n    url: this.url,\n    data: this._data,\n    headers: this._header\n  };\n};\n\n/**\n * Send `data` as the request body, defaulting the `.type()` to \"json\" when\n * an object is given.\n *\n * Examples:\n *\n *       // manual json\n *       request.post('/user')\n *         .type('json')\n *         .send('{\"name\":\"tj\"}')\n *         .end(callback)\n *\n *       // auto json\n *       request.post('/user')\n *         .send({ name: 'tj' })\n *         .end(callback)\n *\n *       // manual x-www-form-urlencoded\n *       request.post('/user')\n *         .type('form')\n *         .send('name=tj')\n *         .end(callback)\n *\n *       // auto x-www-form-urlencoded\n *       request.post('/user')\n *         .type('form')\n *         .send({ name: 'tj' })\n *         .end(callback)\n *\n *       // defaults to x-www-form-urlencoded\n *      request.post('/user')\n *        .send('name=tobi')\n *        .send('species=ferret')\n *        .end(callback)\n *\n * @param {String|Object} data\n * @return {Request} for chaining\n * @api public\n */\n\n// eslint-disable-next-line complexity\nRequestBase.prototype.send = function (data) {\n  const isObject_ = isObject(data);\n  let type = this._header['content-type'];\n\n  if (this._formData) {\n    throw new Error(\n      \".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()\"\n    );\n  }\n\n  if (isObject_ && !this._data) {\n    if (Array.isArray(data)) {\n      this._data = [];\n    } else if (!this._isHost(data)) {\n      this._data = {};\n    }\n  } else if (data && this._data && this._isHost(this._data)) {\n    throw new Error(\"Can't merge these send calls\");\n  }\n\n  // merge\n  if (isObject_ && isObject(this._data)) {\n    for (const key in data) {\n      if (typeof data[key] == 'bigint' && !data[key].toJSON)\n        throw new Error('Cannot serialize BigInt value to json');\n      if (hasOwn(data, key)) this._data[key] = data[key];\n    }\n  }\n  else if (typeof data === 'bigint') throw new Error(\"Cannot send value of type BigInt\");\n  else if (typeof data === 'string') {\n    // default to x-www-form-urlencoded\n    if (!type) this.type('form');\n    type = this._header['content-type'];\n    if (type) type = type.toLowerCase().trim();\n    if (type === 'application/x-www-form-urlencoded') {\n      this._data = this._data ? `${this._data}&${data}` : data;\n    } else {\n      this._data = (this._data || '') + data;\n    }\n  } else {\n    this._data = data;\n  }\n\n  if (!isObject_ || this._isHost(data)) {\n    return this;\n  }\n\n  // default to json\n  if (!type) this.type('json');\n  return this;\n};\n\n/**\n * Sort `querystring` by the sort function\n *\n *\n * Examples:\n *\n *       // default order\n *       request.get('/user')\n *         .query('name=Nick')\n *         .query('search=Manny')\n *         .sortQuery()\n *         .end(callback)\n *\n *       // customized sort function\n *       request.get('/user')\n *         .query('name=Nick')\n *         .query('search=Manny')\n *         .sortQuery(function(a, b){\n *           return a.length - b.length;\n *         })\n *         .end(callback)\n *\n *\n * @param {Function} sort\n * @return {Request} for chaining\n * @api public\n */\n\nRequestBase.prototype.sortQuery = function (sort) {\n  // _sort default to true but otherwise can be a function or boolean\n  this._sort = typeof sort === 'undefined' ? true : sort;\n  return this;\n};\n\n/**\n * Compose querystring to append to req.url\n *\n * @api private\n */\nRequestBase.prototype._finalizeQueryString = function () {\n  const query = this._query.join('&');\n  if (query) {\n    this.url += (this.url.includes('?') ? '&' : '?') + query;\n  }\n\n  this._query.length = 0; // Makes the call idempotent\n\n  if (this._sort) {\n    const index = this.url.indexOf('?');\n    if (index >= 0) {\n      const queryArray = this.url.slice(index + 1).split('&');\n      if (typeof this._sort === 'function') {\n        queryArray.sort(this._sort);\n      } else {\n        queryArray.sort();\n      }\n\n      this.url = this.url.slice(0, index) + '?' + queryArray.join('&');\n    }\n  }\n};\n\n// For backwards compat only\nRequestBase.prototype._appendQueryString = () => {\n  console.warn('Unsupported');\n};\n\n/**\n * Invoke callback with timeout error.\n *\n * @api private\n */\n\nRequestBase.prototype._timeoutError = function (reason, timeout, errno) {\n  if (this._aborted) {\n    return;\n  }\n\n  const error = new Error(`${reason + timeout}ms exceeded`);\n  error.timeout = timeout;\n  error.code = 'ECONNABORTED';\n  error.errno = errno;\n  this.timedout = true;\n  this.timedoutError = error;\n  this.abort();\n  this.callback(error);\n};\n\nRequestBase.prototype._setTimeouts = function () {\n  const self = this;\n\n  // deadline\n  if (this._timeout && !this._timer) {\n    this._timer = setTimeout(() => {\n      self._timeoutError('Timeout of ', self._timeout, 'ETIME');\n    }, this._timeout);\n  }\n\n  // response timeout\n  if (this._responseTimeout && !this._responseTimeoutTimer) {\n    this._responseTimeoutTimer = setTimeout(() => {\n      self._timeoutError(\n        'Response timeout of ',\n        self._responseTimeout,\n        'ETIMEDOUT'\n      );\n    }, this._responseTimeout);\n  }\n};\n"
  },
  {
    "path": "src/response-base.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst utils = require('./utils');\n\n/**\n * Expose `ResponseBase`.\n */\n\nmodule.exports = ResponseBase;\n\n/**\n * Initialize a new `ResponseBase`.\n *\n * @api public\n */\n\nfunction ResponseBase() {}\n\n/**\n * Get case-insensitive `field` value.\n *\n * @param {String} field\n * @return {String}\n * @api public\n */\n\nResponseBase.prototype.get = function (field) {\n  return this.header[field.toLowerCase()];\n};\n\n/**\n * Set header related properties:\n *\n *   - `.type` the content type without params\n *\n * A response of \"Content-Type: text/plain; charset=utf-8\"\n * will provide you with a `.type` of \"text/plain\".\n *\n * @param {Object} header\n * @api private\n */\n\nResponseBase.prototype._setHeaderProperties = function (header) {\n  // TODO: moar!\n  // TODO: make this a util\n\n  // content-type\n  const ct = header['content-type'] || '';\n  this.type = utils.type(ct);\n\n  // params\n  const parameters = utils.params(ct);\n  for (const key in parameters) {\n    if (Object.prototype.hasOwnProperty.call(parameters, key))\n      this[key] = parameters[key];\n  }\n\n  this.links = {};\n\n  // links\n  try {\n    if (header.link) {\n      this.links = utils.parseLinks(header.link);\n    }\n  } catch (err) {\n    // ignore\n  }\n};\n\n/**\n * Set flags such as `.ok` based on `status`.\n *\n * For example a 2xx response will give you a `.ok` of __true__\n * whereas 5xx will be __false__ and `.error` will be __true__. The\n * `.clientError` and `.serverError` are also available to be more\n * specific, and `.statusType` is the class of error ranging from 1..5\n * sometimes useful for mapping respond colors etc.\n *\n * \"sugar\" properties are also defined for common cases. Currently providing:\n *\n *   - .noContent\n *   - .badRequest\n *   - .unauthorized\n *   - .notAcceptable\n *   - .notFound\n *\n * @param {Number} status\n * @api private\n */\n\nResponseBase.prototype._setStatusProperties = function (status) {\n  const type = Math.trunc(status / 100);\n\n  // status / class\n  this.statusCode = status;\n  this.status = this.statusCode;\n  this.statusType = type;\n\n  // basics\n  this.info = type === 1;\n  this.ok = type === 2;\n  this.redirect = type === 3;\n  this.clientError = type === 4;\n  this.serverError = type === 5;\n  this.error = type === 4 || type === 5 ? this.toError() : false;\n\n  // sugar\n  this.created = status === 201;\n  this.accepted = status === 202;\n  this.noContent = status === 204;\n  this.badRequest = status === 400;\n  this.unauthorized = status === 401;\n  this.notAcceptable = status === 406;\n  this.forbidden = status === 403;\n  this.notFound = status === 404;\n  this.unprocessableEntity = status === 422;\n};\n"
  },
  {
    "path": "src/utils.js",
    "content": "\n/**\n * Return the mime type for the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.type = (string_) => string_.split(/ *; */).shift();\n\n/**\n * Return header field parameters.\n *\n * @param {String} str\n * @return {Object}\n * @api private\n */\n\nexports.params = (value) => {\n  const object = {};\n  for (const string_ of value.split(/ *; */)) {\n    const parts = string_.split(/ *= */);\n    const key = parts.shift();\n    const value = parts.shift();\n\n    if (key && value) object[key] = value;\n  }\n\n  return object;\n};\n\n/**\n * Parse Link header fields.\n *\n * @param {String} str\n * @return {Object}\n * @api private\n */\n\nexports.parseLinks = (value) => {\n  const object = {};\n  for (const string_ of value.split(/ *, */)) {\n    const parts = string_.split(/ *; */);\n    const url = parts[0].slice(1, -1);\n    const rel = parts[1].split(/ *= */)[1].slice(1, -1);\n    object[rel] = url;\n  }\n\n  return object;\n};\n\n/**\n * Strip content related fields from `header`.\n *\n * @param {Object} header\n * @return {Object} header\n * @api private\n */\n\nexports.cleanHeader = (header, changesOrigin) => {\n  delete header['content-type'];\n  delete header['content-length'];\n  delete header['transfer-encoding'];\n  delete header.host;\n  // secuirty\n  if (changesOrigin) {\n    delete header.authorization;\n    delete header.cookie;\n  }\n\n  return header;\n};\n\nexports.normalizeHostname = (hostname) => {\n  const [,normalized] = hostname.match(/^\\[([^\\]]+)\\]$/) || [];\n  return normalized || hostname;\n};\n\n/**\n * Check if `obj` is an object.\n *\n * @param {Object} object\n * @return {Boolean}\n * @api private\n */\nexports.isObject = (object) => {\n  return object !== null && typeof object === 'object';\n};\n\n/**\n * Object.hasOwn fallback/polyfill.\n *\n * @type {(object: object, property: string) => boolean} object\n * @api private\n */\nexports.hasOwn =\n  Object.hasOwn ||\n  function (object, property) {\n    if (object == null) {\n      throw new TypeError('Cannot convert undefined or null to object');\n    }\n\n    return Object.prototype.hasOwnProperty.call(new Object(object), property);\n  };\n\nexports.mixin = (target, source) => {\n  for (const key in source) {\n    if (exports.hasOwn(source, key)) {\n      target[key] = source[key];\n    }\n  }\n};\n\n/**\n * Check if the response is compressed using Gzip or Deflate.\n * @param {Object} res\n * @return {Boolean}\n */\n\nexports.isGzipOrDeflateEncoding = (res) => {\n  return new RegExp(/^\\s*(?:deflate|gzip)\\s*$/).test(res.headers['content-encoding']);\n};\n\n/**\n * Check if the response is compressed using Brotli.\n * @param {Object} res\n * @return {Boolean}\n */\n\nexports.isBrotliEncoding = (res) => {\n  return new RegExp(/^\\s*(?:br)\\s*$/).test(res.headers['content-encoding']);\n};\n"
  },
  {
    "path": "test/agent-base.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\ndescribe('Agent', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should remember defaults', () => {\n    if (typeof Promise === 'undefined') {\n      return;\n    }\n\n    let called = 0;\n    let event_called = 0;\n    const agent = request\n      .agent()\n      .accept('json')\n      .use(() => {\n        called++;\n      })\n      .once('request', () => {\n        event_called++;\n      })\n      .query({ hello: 'world' })\n      .set('X-test', 'testing');\n    assert.equal(0, called);\n    assert.equal(0, event_called);\n\n    return agent\n      .get(`${base}/echo`)\n      .then((res) => {\n        assert.equal(1, called);\n        assert.equal(1, event_called);\n        assert.equal('application/json', res.headers.accept);\n        assert.equal('testing', res.headers['x-test']);\n\n        return agent.get(`${base}/querystring`);\n      })\n      .then((res) => {\n        assert.equal(2, called);\n        assert.equal(2, event_called);\n        assert.deepEqual({ hello: 'world' }, res.body);\n      });\n  });\n});\n"
  },
  {
    "path": "test/basic.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\ndescribe('request', function () {\n  let setup;\n  let NODE;\n  let uri;\n\n  before(async () => {\n    setup = await getSetup();\n    NODE = setup.NODE;\n    uri = setup.uri;\n  });\n\n  this.timeout(20_000);\n\n  describe('res.statusCode', () => {\n    it('should set statusCode', (done) => {\n      request.get(`${uri}/login`, (error, res) => {\n        try {\n          assert.strictEqual(res.statusCode, 200);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('should allow the send shorthand', () => {\n    it('with callback in the method call', (done) => {\n      request.get(`${uri}/login`, (error, res) => {\n        assert.equal(res.status, 200);\n        done();\n      });\n    });\n\n    it('with data in the method call', (done) => {\n      request.post(`${uri}/echo`, { foo: 'bar' }).end((error, res) => {\n        assert.equal('{\"foo\":\"bar\"}', res.text);\n        done();\n      });\n    });\n\n    it('with callback and data in the method call', (done) => {\n      request.post(`${uri}/echo`, { foo: 'bar' }, (error, res) => {\n        assert.equal('{\"foo\":\"bar\"}', res.text);\n        done();\n      });\n    });\n  });\n\n  describe('with a callback', () => {\n    it('should invoke .end()', (done) => {\n      request.get(`${uri}/login`, (error, res) => {\n        try {\n          assert.equal(res.status, 200);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('.end()', () => {\n    it('should issue a request', (done) => {\n      request.get(`${uri}/login`).end((error, res) => {\n        try {\n          assert.equal(res.status, 200);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n\n    it('is optional with a promise', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      return request\n        .get(`${uri}/login`)\n        .then((res) => res.status)\n        .then()\n        .then((status) => {\n          assert.equal(200, status, 'Real promises pass results through');\n        });\n    });\n\n    it('called only once with a promise', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      const request_ = request.get(`${uri}/unique`);\n\n      return Promise.all([request_, request_, request_]).then((results) => {\n        for (const item of results) {\n          assert.deepEqual(\n            item.body,\n            results[0].body,\n            'It should keep returning the same result after being called once'\n          );\n        }\n      });\n    });\n  });\n\n  describe('res.error', () => {\n    it('ok', (done) => {\n      let calledErrorEvent = false;\n      let calledOKHandler = false;\n      request\n        .get(`${uri}/error`)\n        .ok((res) => {\n          assert.strictEqual(500, res.status);\n          calledOKHandler = true;\n          return true;\n        })\n        .on('error', (error) => {\n          calledErrorEvent = true;\n        })\n        .end((error, res) => {\n          try {\n            assert.ifError(error);\n            assert.strictEqual(res.status, 500);\n            assert(!calledErrorEvent);\n            assert(calledOKHandler);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should be an Error object', (done) => {\n      let calledErrorEvent = false;\n      request\n        .get(`${uri}/error`)\n        .on('error', (error) => {\n          assert.strictEqual(error.status, 500);\n          calledErrorEvent = true;\n        })\n        .end((error, res) => {\n          try {\n            if (NODE) {\n              res.error.message.should.equal('cannot GET /error (500)');\n            } else {\n              res.error.message.should.equal(`cannot GET ${uri}/error (500)`);\n            }\n\n            assert.strictEqual(res.error.status, 500);\n            assert(error, 'should have an error for 500');\n            assert.equal(error.message, 'Internal Server Error');\n            assert(calledErrorEvent);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('with .then() promise', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      return request.get(`${uri}/error`).then(\n        () => {\n          assert.fail();\n        },\n        (err) => {\n          assert.equal(err.message, 'Internal Server Error');\n        }\n      );\n    });\n\n    it('with .ok() returning false', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      return request\n        .get(`${uri}/echo`)\n        .ok(() => false)\n        .then(\n          () => {\n            assert.fail();\n          },\n          (err) => {\n            assert.equal(200, err.response.status);\n            assert.equal(err.message, 'OK');\n          }\n        );\n    });\n\n    it('with .ok() throwing an Error', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      return request\n        .get(`${uri}/echo`)\n        .ok(() => {\n          throw new Error('boom');\n        })\n        .then(\n          () => {\n            assert.fail();\n          },\n          (err) => {\n            assert.equal(200, err.status);\n            assert.equal(200, err.response.status);\n            assert.equal(err.message, 'boom');\n          }\n        );\n    });\n\n    it('with .ok() throwing an Error with status', () => {\n      if (typeof Promise === 'undefined') {\n        return;\n      }\n\n      return request\n        .get(`${uri}/echo`)\n        .ok(() => {\n          const err = new Error('boom');\n          err.status = 404;\n          throw err;\n        })\n        .then(\n          () => {\n            assert.fail();\n          },\n          (err) => {\n            assert.equal(404, err.status);\n            assert.equal(200, err.response.status);\n            assert.equal(err.message, 'boom');\n          }\n        );\n    });\n  });\n\n  describe('res.header', () => {\n    it('should be an object', (done) => {\n      request.get(`${uri}/login`).end((error, res) => {\n        try {\n          assert.equal('Express', res.header['x-powered-by']);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('set headers', () => {\n    before(() => {\n      Object.prototype.invalid = 'invalid';\n    });\n\n    after(() => {\n      delete Object.prototype.invalid;\n    });\n\n    it('should only set headers for ownProperties of header', (done) => {\n      try {\n        request\n          .get(`${uri}/echo-headers`)\n          .set('valid', 'ok')\n          .end((error, res) => {\n            if (\n              !error &&\n              res.body &&\n              res.body.valid &&\n              !res.body.hasOwnProperty('invalid')\n            ) {\n              return done();\n            }\n\n            done(error || new Error('fail'));\n          });\n      } catch (err) {\n        done(err);\n      }\n    });\n  });\n\n  describe('res.charset', () => {\n    it('should be set when present', (done) => {\n      request.get(`${uri}/login`).end((error, res) => {\n        try {\n          res.charset.should.equal('utf-8');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('res.statusType', () => {\n    it('should provide the first digit', (done) => {\n      request.get(`${uri}/login`).end((error, res) => {\n        try {\n          assert(!error, 'should not have an error for success responses');\n          assert.equal(200, res.status);\n          assert.equal(2, res.statusType);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('res.type', () => {\n    it('should provide the mime-type void of params', (done) => {\n      request.get(`${uri}/login`).end((error, res) => {\n        try {\n          res.type.should.equal('text/html');\n          res.charset.should.equal('utf-8');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('req.set(field, val)', () => {\n    it('should set the header field', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .set('X-Foo', 'bar')\n        .set('X-Bar', 'baz')\n        .end((error, res) => {\n          try {\n            assert.equal('bar', res.header['x-foo']);\n            assert.equal('baz', res.header['x-bar']);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.set(obj)', () => {\n    it('should set the header fields', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .set({ 'X-Foo': 'bar', 'X-Bar': 'baz' })\n        .end((error, res) => {\n          try {\n            assert.equal('bar', res.header['x-foo']);\n            assert.equal('baz', res.header['x-bar']);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.type(str)', () => {\n    it('should set the Content-Type', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .type('text/x-foo')\n        .end((error, res) => {\n          try {\n            res.header['content-type'].should.equal('text/x-foo');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should map \"json\"', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .type('json')\n        .send('{\"a\": 1}')\n        .end((error, res) => {\n          try {\n            res.should.be.json();\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should map \"html\"', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .type('html')\n        .end((error, res) => {\n          try {\n            res.header['content-type'].should.equal('text/html');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.accept(str)', () => {\n    it('should set Accept', (done) => {\n      request\n        .get(`${uri}/echo`)\n        .accept('text/x-foo')\n        .end((error, res) => {\n          try {\n            res.header.accept.should.equal('text/x-foo');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should map \"json\"', (done) => {\n      request\n        .get(`${uri}/echo`)\n        .accept('json')\n        .end((error, res) => {\n          try {\n            res.header.accept.should.equal('application/json');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should map \"xml\"', (done) => {\n      request\n        .get(`${uri}/echo`)\n        .accept('xml')\n        .end((error, res) => {\n          try {\n            // Mime module keeps changing this :(\n            assert(\n              res.header.accept == 'application/xml' ||\n                res.header.accept == 'text/xml'\n            );\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should map \"html\"', (done) => {\n      request\n        .get(`${uri}/echo`)\n        .accept('html')\n        .end((error, res) => {\n          try {\n            res.header.accept.should.equal('text/html');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.send(str)', () => {\n    it('should write the string', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .type('json')\n        .send('{\"name\":\"tobi\"}')\n        .end((error, res) => {\n          try {\n            res.text.should.equal('{\"name\":\"tobi\"}');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.send(Object)', () => {\n    it('should default to json', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .send({ name: 'tobi' })\n        .end((error, res) => {\n          try {\n            res.should.be.json();\n            res.text.should.equal('{\"name\":\"tobi\"}');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    describe('when called several times', () => {\n      it('should merge the objects', (done) => {\n        request\n          .post(`${uri}/echo`)\n          .send({ name: 'tobi' })\n          .send({ age: 1 })\n          .end((error, res) => {\n            try {\n              res.should.be.json();\n              if (NODE) {\n                res.buffered.should.be.true();\n              }\n\n              res.text.should.equal('{\"name\":\"tobi\",\"age\":1}');\n              done();\n            } catch (err) {\n              done(err);\n            }\n          });\n      });\n    });\n  });\n\n  describe('.end(fn)', () => {\n    it('should check arity', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .send({ name: 'tobi' })\n        .end((error, res) => {\n          try {\n            assert.ifError(error);\n            res.text.should.equal('{\"name\":\"tobi\"}');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should emit request', (done) => {\n      const request_ = request.post(`${uri}/echo`);\n      request_.on('request', (request) => {\n        assert.equal(request_, request);\n        done();\n      });\n      request_.end();\n    });\n\n    it('should emit response', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .send({ name: 'tobi' })\n        .on('response', (res) => {\n          res.text.should.equal('{\"name\":\"tobi\"}');\n          done();\n        })\n        .end();\n    });\n  });\n\n  describe('.then(fulfill, reject)', () => {\n    it('should support successful fulfills with .then(fulfill)', (done) => {\n      if (typeof Promise === 'undefined') {\n        return done();\n      }\n\n      request\n        .post(`${uri}/echo`)\n        .send({ name: 'tobi' })\n        .then((res) => {\n          res.type.should.equal('application/json');\n          res.text.should.equal('{\"name\":\"tobi\"}');\n          done();\n        });\n    });\n\n    it('should reject an error with .then(null, reject)', (done) => {\n      if (typeof Promise === 'undefined') {\n        return done();\n      }\n\n      request.get(`${uri}/error`).then(null, (err) => {\n        assert.equal(err.status, 500);\n        assert.equal(err.response.text, 'boom');\n        done();\n      });\n    });\n  });\n\n  describe('.catch(reject)', () => {\n    it('should reject an error with .catch(reject)', (done) => {\n      if (typeof Promise === 'undefined') {\n        return done();\n      }\n\n      request.get(`${uri}/error`).catch((err) => {\n        assert.equal(err.status, 500);\n        assert.equal(err.response.text, 'boom');\n        done();\n      });\n    });\n  });\n\n  describe('.abort()', () => {\n    it('should abort the request', (done) => {\n      const request_ = request.get(`${uri}/delay/3000`);\n      request_.end((error, res) => {\n        try {\n          assert(false, 'should not complete the request');\n        } catch (err) {\n          done(err);\n        }\n      });\n\n      request_.on('error', (error) => {\n        done(error);\n      });\n      request_.on('abort', done);\n\n      setTimeout(() => {\n        request_.abort();\n      }, 500);\n    });\n    it('should abort the promise', () => {\n      const request_ = request.get(`${uri}/delay/3000`);\n      setTimeout(() => {\n        request_.abort();\n      }, 10);\n      return request_.then(\n        () => {\n          assert.fail('should not complete the request');\n        },\n        (err) => {\n          assert.equal('ABORTED', err.code);\n        }\n      );\n    });\n\n    it('should allow chaining .abort() several times', (done) => {\n      const request_ = request.get(`${uri}/delay/3000`);\n      request_.end((error, res) => {\n        try {\n          assert(false, 'should not complete the request');\n        } catch (err) {\n          done(err);\n        }\n      });\n\n      // This also verifies only a single 'done' event is emitted\n      request_.on('abort', done);\n\n      setTimeout(() => {\n        request_.abort().abort().abort();\n      }, 1000);\n    });\n\n    it('should not allow abort then end', (done) => {\n      request\n        .get(`${uri}/delay/3000`)\n        .abort()\n        .end((error, res) => {\n          done(error ? undefined : new Error('Expected abort error'));\n        });\n    });\n  });\n\n  describe('req.toJSON()', () => {\n    it('should describe the request', (done) => {\n      const request_ = request.post(`${uri}/echo`).send({ foo: 'baz' });\n      request_.end((error, res) => {\n        try {\n          const json = request_.toJSON();\n          assert.equal('POST', json.method);\n          assert(/\\/echo$/.test(json.url));\n          assert.equal('baz', json.data.foo);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n  });\n\n  describe('req.options()', () => {\n    it('should allow request body', (done) => {\n      request\n        .options(`${uri}/options/echo/body`)\n        .send({ foo: 'baz' })\n        .end((error, res) => {\n          try {\n            assert.equal(error, null);\n            assert.strictEqual(res.body.foo, 'baz');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('req.sortQuery()', () => {\n    it('nop with no querystring', (done) => {\n      request\n        .get(`${uri}/url`)\n        .sortQuery()\n        .end((error, res) => {\n          try {\n            assert.equal(res.text, '/url');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should sort the request querystring', (done) => {\n      request\n        .get(`${uri}/url`)\n        .query('search=Manny')\n        .query('order=desc')\n        .sortQuery()\n        .end((error, res) => {\n          try {\n            assert.equal(res.text, '/url?order=desc&search=Manny');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should allow disabling sorting', (done) => {\n      request\n        .get(`${uri}/url`)\n        .query('search=Manny')\n        .query('order=desc')\n        .sortQuery() // take default of true\n        .sortQuery(false) // override it in later call\n        .end((error, res) => {\n          try {\n            assert.equal(res.text, '/url?search=Manny&order=desc');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should sort the request querystring using customized function', (done) => {\n      request\n        .get(`${uri}/url`)\n        .query('name=Nick')\n        .query('search=Manny')\n        .query('order=desc')\n        .sortQuery((a, b) => a.length - b.length)\n        .end((error, res) => {\n          try {\n            assert.equal(res.text, '/url?name=Nick&order=desc&search=Manny');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/client/request.js",
    "content": "const assert = require('assert');\nconst request = require('../support/client');\n\ndescribe('request', function () {\n  this.timeout(20_000);\n\n  it('request() error object', (next) => {\n    request('GET', '/error').end((error, res) => {\n      assert(error);\n      assert(res.error, 'response should be an error');\n      assert.equal(res.error.message, 'cannot GET /error (500)');\n      assert.equal(res.error.status, 500);\n      assert.equal(res.error.method, 'GET');\n      assert.equal(res.error.url, '/error');\n      next();\n    });\n  });\n\n  // This test results in a weird Jetty error on IE9 and IE11 saying PATCH is not a supported method. Looks like something's up with SauceLabs\n  const isIE11 = Boolean(/Trident.*rv[ :]*11\\./.test(navigator.userAgent));\n  const isIE9OrOlder = !window.atob;\n  if (!isIE9OrOlder && !isIE11) {\n    // Don't run on IE9 or older, or IE11\n    it('patch()', (next) => {\n      request.patch('/user/12').end((error, res) => {\n        assert.equal('updated', res.text);\n        next();\n      });\n    });\n  }\n\n  it('POST native FormData', (next) => {\n    if (!window.FormData) {\n      // Skip test if FormData is not supported by browser\n      return next();\n    }\n\n    const data = new FormData();\n    data.append('foo', 'bar');\n\n    request\n      .post('/echo')\n      .send(data)\n      .end((error, res) => {\n        assert.equal('multipart/form-data', res.type);\n        next();\n      });\n  });\n\n  it('defaults attached files to original file names', (next) => {\n    if (!window.FormData) {\n      // Skip test if FormData is are not supported by browser\n      return next();\n    }\n\n    try {\n      var file = new File([''], 'image.jpg', { type: 'image/jpeg' });\n    } catch (err) {\n      // Skip if file constructor not supported.\n      return next();\n    }\n\n    request\n      .post('/echo')\n      .attach('image', file)\n      .end((error, res) => {\n        const regx = new RegExp(`filename=\"${file.name}\"`);\n        assert.notEqual(res.text.match(regx), null);\n        next();\n      });\n  });\n\n  it('attach() cannot be mixed with send()', () => {\n    if (!window.FormData || !window.File) {\n      // Skip test if FormData is are not supported by browser\n      return;\n    }\n\n    assert.throws(() => {\n      const file = new File([''], 'image.jpg', { type: 'image/jpeg' });\n      request.post('/echo').attach('image', file).send('hi');\n    });\n\n    assert.throws(() => {\n      const file = new File([''], 'image.jpg', { type: 'image/jpeg' });\n      request.post('/echo').send('hi').attach('image', file);\n    });\n  });\n\n  it('GET invalid json', (next) => {\n    request.get('/invalid-json').end((error, res) => {\n      assert(error.parse);\n      assert.deepEqual(\n        error.rawResponse,\n        \")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}\"\n      );\n      next();\n    });\n  });\n\n  it('GET querystring empty objects', (next) => {\n    const request_ = request.get('/querystring').query({});\n    request_.end((error, res) => {\n      assert.deepEqual(request_._query, []);\n      assert.deepEqual(res.body, {});\n      next();\n    });\n  });\n\n  it('GET querystring object .get(uri, obj)', (next) => {\n    request.get('/querystring', { search: 'Manny' }).end((error, res) => {\n      assert.deepEqual(res.body, { search: 'Manny' });\n      next();\n    });\n  });\n\n  it('GET querystring object .get(uri, obj, fn)', (next) => {\n    request.get('/querystring', { search: 'Manny' }, (error, res) => {\n      assert.deepEqual(res.body, { search: 'Manny' });\n      next();\n    });\n  });\n\n  it('GET querystring object with null value', (next) => {\n    request.get('/url', { nil: null }).end((error, res) => {\n      assert.equal(res.text, '/url?nil');\n      next();\n    });\n  });\n\n  it('GET blob object', (next) => {\n    if (typeof Blob === 'undefined') {\n      return next();\n    }\n\n    request\n      .get('/blob', { foo: 'bar' })\n      .responseType('blob')\n      .end((error, res) => {\n        assert(res.xhr.response instanceof Blob);\n        assert(res.body instanceof Blob);\n        next();\n      });\n  });\n\n  it('Reject node-only function', () => {\n    assert.throws(() => {\n      request.get().write();\n    });\n    assert.throws(() => {\n      request.get().pipe();\n    });\n  });\n\n  window.btoa = window.btoa || null;\n  it('basic auth', (next) => {\n    window.btoa = window.btoa || require('Base64').btoa;\n\n    request\n      .post('/auth')\n      .auth('foo', 'bar')\n      .end((error, res) => {\n        assert.equal('foo', res.body.user);\n        assert.equal('bar', res.body.pass);\n        next();\n      });\n  });\n\n  it('auth type \"basic\"', (next) => {\n    window.btoa = window.btoa || require('Base64').btoa;\n\n    request\n      .post('/auth')\n      .auth('foo', 'bar', { type: 'basic' })\n      .end((error, res) => {\n        assert.equal('foo', res.body.user);\n        assert.equal('bar', res.body.pass);\n        next();\n      });\n  });\n\n  it('auth type \"auto\"', (next) => {\n    window.btoa = window.btoa || require('Base64').btoa;\n\n    request\n      .post('/auth')\n      .auth('foo', 'bar', { type: 'auto' })\n      .end((error, res) => {\n        assert.equal('foo', res.body.user);\n        assert.equal('bar', res.body.pass);\n        next();\n      });\n  });\n\n  it('progress event listener on xhr object registered when some on the request', () => {\n    const request_ = request.get('/foo').on('progress', (data) => {});\n    request_.end();\n\n    if (request_.xhr.upload) {\n      // Only run assertion on capable browsers\n      assert.notEqual(null, request_.xhr.upload.onprogress);\n    }\n  });\n\n  it('no progress event listener on xhr object when none registered on request', () => {\n    const request_ = request.get('/foo');\n    request_.end();\n\n    if (request_.xhr.upload) {\n      // Only run assertion on capable browsers\n      assert.strictEqual(null, request_.xhr.upload.onprogress);\n    }\n  });\n\n  it('Request#parse overrides body parser no matter Content-Type', (done) => {\n    let runParser = false;\n\n    function testParser(data) {\n      runParser = true;\n      return JSON.stringify(data);\n    }\n\n    request\n      .post('/user')\n      .serialize(testParser)\n      .type('json')\n      .send({ foo: 123 })\n      .end((error) => {\n        if (error) return done(error);\n        assert(runParser);\n        done();\n      });\n  });\n\n  // Don't run on browsers without xhr2 support\n  if ('FormData' in window) {\n    it('xhr2 download file old hack', (next) => {\n      request.parse['application/vnd.superagent'] = (object) => object;\n\n      request\n        .get('/arraybuffer')\n        .on('request', function () {\n          this.xhr.responseType = 'arraybuffer';\n        })\n        .on('response', (res) => {\n          assert(res.body instanceof ArrayBuffer);\n          next();\n        })\n        .end();\n    });\n\n    it('xhr2 download file responseType', (next) => {\n      request.parse['application/vnd.superagent'] = (object) => object;\n\n      request\n        .get('/arraybuffer')\n        .responseType('arraybuffer')\n        .on('response', (res) => {\n          assert(res.body instanceof ArrayBuffer);\n          next();\n        })\n        .end();\n    });\n\n    it('get error status code and rawResponse on file download', (next) => {\n      request\n        .get('/arraybuffer-unauthorized')\n        .responseType('arraybuffer')\n        .end((error, res) => {\n          assert.equal(error.status, 401);\n          assert(res.body instanceof ArrayBuffer);\n          assert(error.response.body instanceof ArrayBuffer);\n          const decodedString = String.fromCharCode.apply(\n            null,\n            new Uint8Array(res.body)\n          );\n          assert(\n            decodedString,\n            '{\"message\":\"Authorization has been denied for this request.\"}'\n          );\n          next();\n        });\n    });\n  }\n\n  it('parse should take precedence over default parse', (done) => {\n    request\n      .get('/foo')\n      .parse((res, text) => `customText: ${res.status}`)\n      .end((error, res) => {\n        assert(res.ok);\n        assert(res.body === 'customText: 200');\n        done();\n      });\n  });\n\n  it('handles `xhr.open()` errors', (done) => {\n    request\n      .get('http://foo\\0.com') // throws \"Failed to execute 'open' on 'XMLHttpRequest': Invalid URL\"\n      .end((error, res) => {\n        assert(error);\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "test/client/serialize.js",
    "content": "const assert = require('assert');\n\nconst request = require('../support/client');\n\nfunction serialize(object, res) {\n  const value = request.serializeObject(object);\n  assert.equal(\n    value,\n    res,\n    `${JSON.stringify(\n      object\n    )} to \"${res}\" serialization failed. got: \"${value}\"`\n  );\n}\n\nfunction parse(string_, object) {\n  const value = request.parseString(string_);\n  assert.deepEqual(\n    value,\n    object,\n    `\"${string_}\" to ${JSON.stringify(\n      object\n    )} parse failed. got: ${JSON.stringify(value)}`\n  );\n}\n\ndescribe('request.serializeObject()', () => {\n  it('should serialize', () => {\n    serialize('test', 'test');\n    serialize('foo=bar', 'foo=bar');\n    serialize({ foo: 'bar' }, 'foo=bar');\n    serialize({ foo: null }, 'foo');\n    serialize({ foo: 'null' }, 'foo=null');\n    serialize({ foo: undefined }, '');\n    serialize({ foo: 'undefined' }, 'foo=undefined');\n    serialize({ name: 'tj', age: 24 }, 'name=tj&age=24');\n    serialize({ name: '&tj&' }, 'name=%26tj%26');\n    serialize({ '&name&': 'tj' }, '%26name%26=tj');\n    serialize({ hello: '`test`' }, 'hello=%60test%60');\n    serialize({ $hello: 'test' }, '$hello=test');\n    // eslint-disable-next-line no-dupe-keys\n    serialize({ foo: 'foo', foo: 'bar' }, 'foo=foo&foo=bar');\n  });\n});\n\ndescribe('request.parseString()', () => {\n  it('should parse', () => {\n    parse('name=tj', { name: 'tj' });\n    parse('name=Manny&species=cat', { name: 'Manny', species: 'cat' });\n    parse('redirect=/&ok', { redirect: '/', ok: '' });\n    parse('%26name=tj', { '&name': 'tj' });\n    parse('name=tj%26', { name: 'tj&' });\n    parse('%60', { '`': '' });\n  });\n});\n\ndescribe('Merging objects', () => {\n  it(\"Don't mix FormData and JSON\", () => {\n    if (!window.FormData) {\n      // Skip test if FormData is not supported by browser\n      return;\n    }\n\n    const data = new FormData();\n    data.append('foo', 'bar');\n\n    assert.throws(() => {\n      request.post('/echo').send(data).send({ allowed: false });\n    });\n  });\n\n  it(\"Don't mix Blob and JSON\", () => {\n    if (!window.Blob) {\n      return;\n    }\n\n    request\n      .post('/echo')\n      .send(new Blob(['will be cleared']))\n      .send(false)\n      .send({ allowed: true });\n\n    assert.throws(() => {\n      request\n        .post('/echo')\n        .send(new Blob(['hello']))\n        .send({ allowed: false });\n    });\n  });\n});\n"
  },
  {
    "path": "test/client/xdomain.js",
    "content": "const assert = require('assert');\nconst request = require('../support/client');\n\ndescribe('xdomain', function () {\n  this.timeout(20_000);\n\n  // TODO (defunctzombie) I am not certain this actually forces xdomain request\n  // use localtunnel.me and tunnel127.com alias instead\n  it('should support req.withCredentials()', (next) => {\n    request\n      .get(`//${window.location.host}/xdomain`)\n      .withCredentials()\n      .end((error, res) => {\n        assert.equal(200, res.status);\n        assert.equal('tobi', res.text);\n        next();\n      });\n  });\n\n  // xdomain not supported in old IE and IE11 gives weird Jetty errors (looks like a SauceLabs issue)\n  const isIE11 = Boolean(/Trident.*rv[ :]*11\\./.test(navigator.userAgent));\n  const isIE9OrOlder = !window.atob;\n  if (!isIE9OrOlder && !isIE11) {\n    // Don't run on IE9 or older, or IE11\n    it('should handle x-domain failure', (next) => {\n      request.get('//tunne127.com').end((error, res) => {\n        assert(error, 'error missing');\n        assert(error.crossDomain, 'not .crossDomain');\n        next();\n      });\n    });\n\n    it('should handle x-domain failure after repeat attempts', (next) => {\n      request\n        .get('//tunne127.com')\n        .retry(2)\n        .end((error, res) => {\n          try {\n            assert(error, 'error missing');\n            assert(error.crossDomain, 'not .crossDomain');\n            assert.equal(2, error.retries, 'expected an error with .retries');\n            next();\n          } catch (err) {\n            next(err);\n          }\n        });\n    });\n  }\n});\n"
  },
  {
    "path": "test/content-type.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\ndescribe('req.set(\"Content-Type\", contentType)', function () {\n  let setup;\n  let uri;\n\n  before(async () => {\n    setup = await getSetup();\n    uri = setup.uri;\n  });\n\n  this.timeout(20_000);\n\n  it('should work with just the contentType component', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .set('Content-Type', 'application/json')\n      .send({ name: 'tobi' })\n      .end((error) => {\n        assert(!error);\n        done();\n      });\n  });\n\n  it('should work with the charset component', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .set('Content-Type', 'application/json; charset=utf-8')\n      .send({ name: 'tobi' })\n      .end((error) => {\n        assert(!error);\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "test/form.js",
    "content": "const assert = require('assert');\nconst should = require('should');\n\nconst getSetup = require('./support/setup');\nconst request = require('./support/client');\n\nif (!assert.deepStrictEqual) assert.deepStrictEqual = assert.deepEqual;\n\ndescribe('req.send(Object) as \"form\"', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('with req.type() set to form', () => {\n    it('should send x-www-form-urlencoded data', (done) => {\n      request\n        .post(`${base}/echo`)\n        .type('form')\n        .send({ name: 'tobi' })\n        .end((error, res) => {\n          res.header['content-type'].should.equal(\n            'application/x-www-form-urlencoded'\n          );\n          res.text.should.equal('name=tobi');\n          done();\n        });\n    });\n  });\n\n  describe('when called several times', () => {\n    it('should merge the objects', (done) => {\n      request\n        .post(`${base}/echo`)\n        .type('form')\n        .send({ name: { first: 'tobi', last: 'holowaychuk' } })\n        .send({ age: '1' })\n        .end((error, res) => {\n          res.header['content-type'].should.equal(\n            'application/x-www-form-urlencoded'\n          );\n          res.text.should.equal(\n            'name%5Bfirst%5D=tobi&name%5Blast%5D=holowaychuk&age=1'\n          );\n          done();\n        });\n    });\n  });\n});\n\ndescribe('req.attach', () => {\n  it('ignores null file', (done) => {\n    request\n      .post('/echo')\n      .attach('image', null)\n      .end((error, res) => {\n        done();\n      });\n  });\n});\n\ndescribe('req.field', function () {\n  let setup;\n  let base;\n  let formDataSupported;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n\n    formDataSupported = setup.NODE || FormData !== 'undefined';\n  });\n\n  this.timeout(5000);\n  it('allow bools', (done) => {\n    if (!formDataSupported) {\n      return done();\n    }\n\n    request\n      .post(`${base}/formecho`)\n      .field('bools', true)\n      .field('strings', 'true')\n      .end((error, res) => {\n        assert.ifError(error);\n        assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' });\n        done();\n      });\n  });\n\n  it('allow objects', (done) => {\n    if (!formDataSupported) {\n      return done();\n    }\n\n    request\n      .post(`${base}/formecho`)\n      .field({ bools: true, strings: 'true' })\n      .end((error, res) => {\n        assert.ifError(error);\n        assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' });\n        done();\n      });\n  });\n\n  it('works with arrays in objects', (done) => {\n    if (!formDataSupported) {\n      return done();\n    }\n\n    request\n      .post(`${base}/formecho`)\n      .field({ numbers: [1, 2, 3] })\n      .end((error, res) => {\n        assert.ifError(error);\n        assert.deepStrictEqual(res.body, { numbers: ['1', '2', '3'] });\n        done();\n      });\n  });\n\n  it('works with arrays', (done) => {\n    if (!formDataSupported) {\n      return done();\n    }\n\n    request\n      .post(`${base}/formecho`)\n      .field('letters', ['a', 'b', 'c'])\n      .end((error, res) => {\n        assert.ifError(error);\n        assert.deepStrictEqual(res.body, { letters: ['a', 'b', 'c'] });\n        done();\n      });\n  });\n\n  it('throw when empty', () => {\n    should.throws(() => {\n      request.post(`${base}/echo`).field();\n    }, /name/);\n\n    should.throws(() => {\n      request.post(`${base}/echo`).field('name');\n    }, /val/);\n  });\n\n  it('cannot be mixed with send()', () => {\n    assert.throws(() => {\n      request.post('/echo').field('form', 'data').send('hi');\n    });\n\n    assert.throws(() => {\n      request.post('/echo').send('hi').field('form', 'data');\n    });\n  });\n});\n"
  },
  {
    "path": "test/json.js",
    "content": "const getSetup = require('./support/setup');\n\nconst doesntWorkInHttp2 = !process.env.HTTP2_TEST;\n\nconst assert = require('assert');\nconst request = require('./support/client');\n\ndescribe('req.send(Object) as \"json\"', function () {\n  let setup;\n  let uri;\n  let doesntWorkInBrowserYet;\n\n  before(async () => {\n    setup = await getSetup();\n    uri = setup.uri;\n    doesntWorkInBrowserYet = setup.NODE;\n  });\n\n  this.timeout(20_000);\n\n  it('should default to json', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .send({ name: 'tobi' })\n      .end((error, res) => {\n        res.should.be.json();\n        res.text.should.equal('{\"name\":\"tobi\"}');\n        done();\n      });\n  });\n\n  it('should work with arrays', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .send([1, 2, 3])\n      .end((error, res) => {\n        res.should.be.json();\n        res.text.should.equal('[1,2,3]');\n        done();\n      });\n  });\n\n  it('should work with value null', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .type('json')\n      .send('null')\n      .end((error, res) => {\n        res.should.be.json();\n        assert.strictEqual(res.body, null);\n        done();\n      });\n  });\n\n  it('should work with value false', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .type('json')\n      .send('false')\n      .end((error, res) => {\n        res.should.be.json();\n        res.body.should.equal(false);\n        done();\n      });\n  });\n\n  if (doesntWorkInBrowserYet)\n    it('should work with value 0', (done) => {\n      // fails in IE9\n      request\n        .post(`${uri}/echo`)\n        .type('json')\n        .send('0')\n        .end((error, res) => {\n          res.should.be.json();\n          res.body.should.equal(0);\n          done();\n        });\n    });\n\n  it('should work with empty string value', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .type('json')\n      .send('\"\"')\n      .end((error, res) => {\n        res.should.be.json();\n        res.body.should.equal('');\n        done();\n      });\n  });\n\n  if (doesntWorkInBrowserYet && doesntWorkInHttp2)\n    it('should work with GET', (done) => {\n      request\n        .get(`${uri}/echo`)\n        .send({ tobi: 'ferret' })\n        .end((error, res) => {\n          try {\n            res.should.be.json();\n            res.text.should.equal('{\"tobi\":\"ferret\"}');\n            ({ tobi: 'ferret' }.should.eql(res.body));\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n  it('should work with vendor MIME type', (done) => {\n    request\n      .post(`${uri}/echo`)\n      .set('Content-Type', 'application/vnd.example+json')\n      .send({ name: 'vendor' })\n      .end((error, res) => {\n        res.text.should.equal('{\"name\":\"vendor\"}');\n        ({ name: 'vendor' }.should.eql(res.body));\n        done();\n      });\n  });\n\n  it('should error for BigInt object', (done) => {\n    try {\n      request\n        .post(`${uri}/echo`)\n        .type('json')\n        .send({number: 1n})\n        throw new Error('Should have thrown error for object with BigInt')\n    } catch (error) {\n      assert.strictEqual(error.message, 'Cannot serialize BigInt value to json');\n    }\n    done();\n  });\n\n  describe('when BigInts have a .toJSON property', function () {\n    before(function () {\n      // eslint-disable-next-line node/no-unsupported-features/es-builtins\n      BigInt.prototype.toJSON = function () {\n        return this.toString();\n      };\n    });\n\n    it('should accept BigInt properties', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .send({ number: 1n })\n        .end((error, res) => {\n          res.should.be.json();\n          res.text.should.equal('{\"number\":\"1\"}');\n          done();\n        });\n    });\n\n    after(function () {\n      // eslint-disable-next-line node/no-unsupported-features/es-builtins\n      delete BigInt.prototype.toJSON;\n    });\n  });\n\n\n  it('should error for BigInt primitive', (done) => {\n    try {\n      request\n        .post(`${uri}/echo`)\n        .type('json')\n        .send(1n)\n        throw new Error('Should have thrown error for BigInt primitive')\n    } catch (error) {\n      assert.strictEqual(error.message, 'Cannot send value of type BigInt');\n    }\n    done();\n  });\n\n  describe('when called several times', () => {\n    it('should merge the objects', (done) => {\n      request\n        .post(`${uri}/echo`)\n        .send({ name: 'tobi' })\n        .send({ age: 1 })\n        .end((error, res) => {\n          res.should.be.json();\n          res.text.should.equal('{\"name\":\"tobi\",\"age\":1}');\n          ({ name: 'tobi', age: 1 }.should.eql(res.body));\n          done();\n        });\n    });\n  });\n});\n\ndescribe('res.body', function () {\n  let setup;\n  let uri;\n  let doesntWorkInBrowserYet;\n\n  before(async () => {\n    setup = await getSetup();\n    uri = setup.uri;\n    doesntWorkInBrowserYet = setup.NODE;\n  });\n\n  this.timeout(20_000);\n\n  describe('application/json', () => {\n    it('should parse the body', (done) => {\n      request.get(`${uri}/json`).end((error, res) => {\n        res.text.should.equal('{\"name\":\"manny\"}');\n        res.body.should.eql({ name: 'manny' });\n        done();\n      });\n    });\n  });\n\n  if (doesntWorkInBrowserYet)\n    describe('HEAD requests', () => {\n      it('should not throw a parse error', (done) => {\n        request.head(`${uri}/json`).end((error, res) => {\n          try {\n            assert.strictEqual(error, null);\n            assert.strictEqual(res.text, undefined);\n            assert.strictEqual(Object.keys(res.body).length, 0);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n      });\n    });\n\n  describe('Invalid JSON response', () => {\n    it('should return the raw response', (done) => {\n      request.get(`${uri}/invalid-json`).end((error, res) => {\n        assert.deepEqual(\n          error.rawResponse,\n          \")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}\"\n        );\n        done();\n      });\n    });\n\n    it('should return the http status code', (done) => {\n      request.get(`${uri}/invalid-json-forbidden`).end((error, res) => {\n        assert.equal(error.statusCode, 403);\n        done();\n      });\n    });\n  });\n\n  if (doesntWorkInBrowserYet)\n    describe('No content', () => {\n      it('should not throw a parse error', (done) => {\n        request.get(`${uri}/no-content`).end((error, res) => {\n          try {\n            assert.strictEqual(error, null);\n            assert.strictEqual(res.text, '');\n            assert.strictEqual(Object.keys(res.body).length, 0);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n      });\n    });\n\n  if (doesntWorkInBrowserYet)\n    describe('application/json+hal', () => {\n      it('should parse the body', (done) => {\n        request.get(`${uri}/json-hal`).end((error, res) => {\n          if (error) return done(error);\n          res.text.should.equal('{\"name\":\"hal 5000\"}');\n          res.body.should.eql({ name: 'hal 5000' });\n          done();\n        });\n      });\n    });\n\n  if (doesntWorkInBrowserYet)\n    describe('vnd.collection+json', () => {\n      it('should parse the body', (done) => {\n        request.get(`${uri}/collection-json`).end((error, res) => {\n          res.text.should.equal('{\"name\":\"chewbacca\"}');\n          res.body.should.eql({ name: 'chewbacca' });\n          done();\n        });\n      });\n    });\n});\n"
  },
  {
    "path": "test/node/agency.js",
    "content": "'use strict';\n\nconst express = require('../support/express');\n\nconst app = express();\nconst request = require('../support/client');\nconst assert = require('assert');\nconst cookieParser = require('cookie-parser');\nconst cookiejar = require('cookiejar');\nconst session = require('express-session');\nlet http = require('http');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n  http.Http2ServerResponse.prototype._implicitHeader = function () {\n    this.writeHead(this.statusCode);\n  };\n}\n\napp.use(cookieParser());\napp.use(\n  session({\n    secret: 'secret',\n    resave: true,\n    saveUninitialized: true\n  })\n);\n\napp.post('/signin', (request_, res) => {\n  request_.session.user = 'hunter@hunterloftis.com';\n  res.redirect('/dashboard');\n});\n\napp.post('/setcookie', (request_, res) => {\n  res.cookie('cookie', 'jar');\n  res.sendStatus(200);\n});\n\napp.get('/getcookie', (request_, res) => {\n  res.status(200).send(request_.cookies.cookie);\n});\n\napp.get('/cookieheader', (request_, res) => {\n  res.status(200).send(request_.headers.cookie);\n});\n\napp.get('/dashboard', (request_, res) => {\n  if (request_.session.user) return res.status(200).send('dashboard');\n  res.status(401).send('dashboard');\n});\n\napp.all('/signout', (request_, res) => {\n  request_.session.regenerate(() => {\n    res.status(200).send('signout');\n  });\n});\n\napp.get('/', (request_, res) => {\n  if (request_.session.user) return res.redirect('/dashboard');\n  res.status(200).send('home');\n});\n\napp.post('/redirect', (request_, res) => {\n  res.redirect('/simple');\n});\n\napp.get('/simple', (request_, res) => {\n  res.status(200).send('simple');\n});\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server = server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\ndescribe('request', () => {\n  describe('persistent agent', () => {\n    const agent1 = request.agent();\n    const agent2 = request.agent();\n    const agent3 = request.agent();\n    const agent4 = request.agent();\n\n    it('should gain a session on POST', () =>\n      agent3.post(`${base}/signin`).then((res) => {\n        assert.equal(res.status, 200);\n        assert.ok('set-cookie' in res.headers === false);\n        assert.equal(res.text, 'dashboard');\n      }));\n\n    it('should start with empty session (set cookies)', (done) => {\n      agent1.get(`${base}/dashboard`).end((error, res) => {\n        assert.ok(error instanceof Error);\n        assert.equal(res.status, 401);\n        assert.ok('set-cookie' in res.headers);\n        done();\n      });\n    });\n\n    it('should gain a session (cookies already set)', () =>\n      agent1.post(`${base}/signin`).then((res) => {\n        assert.equal(res.status, 200);\n        assert.ok('set-cookie' in res.headers === false);\n        assert.equal('dashboard', res.text);\n      }));\n\n    it('should persist cookies across requests', () =>\n      agent1.get(`${base}/dashboard`).then((res) => {\n        assert.equal(res.status, 200);\n      }));\n\n    it('should have the cookie set in the end callback', () =>\n      agent4\n        .post(`${base}/setcookie`)\n        .then(() => agent4.get(`${base}/getcookie`))\n        .then((res) => {\n          assert.equal(res.status, 200);\n          assert.strictEqual(res.text, 'jar');\n        }));\n\n    it('should produce a valid cookie header', (done) => {\n      agent4\n        .set('Cookie', 'first_cookie=dummy; cookie=jam')\n        .get(`${base}/cookieheader`)\n        .then((res) => {\n          const cookiePairs = res.text.split('; '); // https://httpwg.org/specs/rfc6265.html#rfc.section.4.2.1\n          assert.deepStrictEqual(cookiePairs, [\n            'first_cookie=dummy',\n            'cookie=jar',\n            `connect.sid=${agent4.jar.getCookie('connect.sid', cookiejar.CookieAccessInfo.All).value}`,\n          ]);\n          done();\n        });\n    });\n\n    it('should not share cookies between domains', () => {\n      assert.equal(agent4.get('https://google.com').cookies, \"\");\n    });\n\n    it('should send cookies to allowed domain with a different path', () => {\n      const postRequest = agent4.post(`${base}/x/y/z`)\n      const cookiesNames = postRequest.cookies.split(';').map(cookie => cookie.split('=')[0])\n      assert.deepStrictEqual(cookiesNames, ['cookie', ' connect.sid']);\n    });\n\n    it('should not share cookies', (done) => {\n      agent2.get(`${base}/dashboard`).end((error, res) => {\n        assert.ok(error instanceof Error);\n        assert.equal(res.status, 401);\n        done();\n      });\n    });\n\n    it('should not lose cookies between agents', () =>\n      agent1.get(`${base}/dashboard`).then((res) => {\n        assert.equal(res.status, 200);\n      }));\n\n    it('should be able to follow redirects', () =>\n      agent1.get(base).then((res) => {\n        assert.equal(res.status, 200);\n        assert.equal(res.text, 'dashboard');\n      }));\n\n    it('should be able to post redirects', () =>\n      agent1\n        .post(`${base}/redirect`)\n        .send({ foo: 'bar', baz: 'blaaah' })\n        .then((res) => {\n          assert.equal(res.status, 200);\n          assert.equal(res.text, 'simple');\n          assert.deepStrictEqual(res.redirects, [`${base}/simple`]);\n        }));\n\n    it('should be able to limit redirects', (done) => {\n      agent1\n        .get(base)\n        .redirects(0)\n        .end((error, res) => {\n          assert.ok(error instanceof Error);\n          assert.equal(res.status, 302);\n          assert.deepEqual(res.redirects, []);\n          assert.equal(res.header.location, '/dashboard');\n          done();\n        });\n    });\n\n    it('should be able to create a new session (clear cookie)', () =>\n      agent1.post(`${base}/signout`).then((res) => {\n        assert.equal(res.status, 200);\n        assert.ok('set-cookie' in res.headers);\n      }));\n\n    it('should regenerate with an empty session', (done) => {\n      agent1.get(`${base}/dashboard`).end((error, res) => {\n        assert.ok(error instanceof Error);\n        assert.equal(res.status, 401);\n        assert.ok('set-cookie' in res.headers === false);\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/basic-auth.js",
    "content": "const assert = require('assert');\nconst { format } = require('url');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('Basic auth', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('when credentials are present in url', () => {\n    it('should set Authorization', (done) => {\n      const new_url = new URL(base);\n      new_url.username = 'tobi';\n      new_url.password = 'learnboost';\n      new_url.pathname = '/basic-auth';\n\n      request.get(format(new_url)).end((error, res) => {\n        assert.equal(res.status, 200);\n        done();\n      });\n    });\n  });\n\n  describe('req.auth(user, pass)', () => {\n    it('should set Authorization', (done) => {\n      request\n        .get(`${base}/basic-auth`)\n        .auth('tobi', 'learnboost')\n        .end((error, res) => {\n          assert.equal(res.status, 200);\n          done();\n        });\n    });\n  });\n\n  describe('req.auth(user + \":\" + pass)', () => {\n    it('should set authorization', (done) => {\n      request\n        .get(`${base}/basic-auth/again`)\n        .auth('tobi')\n        .end((error, res) => {\n          assert.equal(res.status, 200);\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/basic.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst { EventEmitter } = require('events');\nconst { StringDecoder } = require('string_decoder');\nconst getSetup = require('../support/setup');\nconst request = require('../support/client');\n\nconst doesntWorkInHttp2 = !process.env.HTTP2_TEST;\n\ndescribe('[node] request', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('with an url', () => {\n    it('should preserve the encoding of the url', (done) => {\n      request.get(`${base}/url?a=(b%29`).end((error, res) => {\n        assert.equal('/url?a=(b%29', res.text);\n        done();\n      });\n    });\n  });\n\n  describe('with an object', () => {\n    it('should format the url', () =>\n      request.get(new URL(`${base}/login`)).then((res) => {\n        assert.ok(res.ok);\n      }));\n  });\n\n  describe('without a schema', () => {\n    it('should default to http', () =>\n      request.get(`${base}/login`).then((res) => {\n        assert.equal(res.status, 200);\n      }));\n  });\n\n  describe('res.toJSON()', () => {\n    it('should describe the response', () =>\n      request\n        .post(`${base}/echo`)\n        .send({ foo: 'baz' })\n        .then((res) => {\n          const object = res.toJSON();\n          assert.equal('object', typeof object.header);\n          assert.equal('object', typeof object.req);\n          assert.equal(200, object.status);\n          assert.equal('{\"foo\":\"baz\"}', object.text);\n        }));\n  });\n\n  describe('res.links', () => {\n    it('should default to an empty object', () =>\n      request.get(`${base}/login`).then((res) => {\n        assert.deepEqual(res.links, {});\n      }));\n\n    it('should parse the Link header field', (done) => {\n      request.get(`${base}/links`).end((error, res) => {\n        assert.equal(\n          res.links.next,\n          'https://api.github.com/repos/visionmedia/mocha/issues?page=2'\n        );\n        done();\n      });\n    });\n  });\n\n  describe('req.unset(field)', () => {\n    it('should remove the header field', (done) => {\n      request\n        .post(`${base}/echo`)\n        .unset('User-Agent')\n        .end((error, res) => {\n          assert.equal(res.header['user-agent'], undefined);\n          done();\n        });\n    });\n  });\n\n  describe('case-insensitive', () => {\n    it('should set/get header fields case-insensitively', () => {\n      const req = request.post(`${base}/echo`);\n      req.set('MiXeD', 'helloes');\n      assert.strictEqual(req.get('mixed'), 'helloes');\n    });\n\n    it('should unset header fields case-insensitively', () => {\n      const req = request.post(`${base}/echo`);\n      req.set('MiXeD', 'helloes');\n      req.unset('MIXED');\n      assert.strictEqual(req.get('mixed'), undefined);\n    });\n  });\n\n  describe('req.write(str)', () => {\n    it('should write the given data', (done) => {\n      const request_ = request.post(`${base}/echo`);\n      request_.set('Content-Type', 'application/json');\n      assert.equal('boolean', typeof request_.write('{\"name\"'));\n      assert.equal('boolean', typeof request_.write(':\"tobi\"}'));\n      request_.end((error, res) => {\n        assert.equal(res.text, '{\"name\":\"tobi\"}');\n        done();\n      });\n    });\n  });\n\n  describe('req.pipe(stream)', () => {\n    it('should pipe the response to the given stream', (done) => {\n      const stream = new EventEmitter();\n\n      let buf = '';\n      stream.writable = true;\n\n      stream.write = function (chunk) {\n        buf += chunk;\n      };\n\n      stream.end = function () {\n        assert.equal(buf, '{\"name\":\"tobi\"}');\n        done();\n      };\n\n      request.post(`${base}/echo`)\n        .send('{\"name\":\"tobi\"}')\n        .pipe(stream);\n    });\n  });\n\n  describe('ipv6 address', () => {\n    it('should successfully query an ipv6 address', (done) => {\n      request.get(`http://[::]:${process.env.ZUUL_PORT}/url?a=(b%29`).end((error, res) => {\n        assert.equal('/url?a=(b%29', res.text);\n        done();\n      });\n    });\n\n    it('should successfully query an ipv6 address', (done) => {\n      request.get(`http://[::1]:${process.env.ZUUL_PORT}/url?a=(b%29`).end((error, res) => {\n        assert.equal('/url?a=(b%29', res.text);\n        done();\n      });\n    });\n  });\n\n  describe('.buffer()', () => {\n    it('should enable buffering', (done) => {\n      request\n        .get(`${base}/custom`)\n        .buffer()\n        .end((error, res) => {\n          assert.ifError(error);\n          assert.equal('custom stuff', res.text);\n          assert.ok(res.buffered);\n          done();\n        });\n    });\n    it(\"should take precedence over request.buffer['someMimeType'] = false\", (done) => {\n      const type = 'application/barbaz';\n      const send = 'some text';\n      request.buffer[type] = false;\n      request\n        .post(`${base}/echo`)\n        .type(type)\n        .send(send)\n        .buffer()\n        .end((error, res) => {\n          delete request.buffer[type];\n          assert.ifError(error);\n          assert.equal(res.type, type);\n          assert.equal(send, res.text);\n          assert.ok(res.buffered);\n          done();\n        });\n    });\n  });\n\n  describe('.buffer(false)', () => {\n    it('should disable buffering', (done) => {\n      request\n        .post(`${base}/echo`)\n        .type('application/x-dog')\n        .send('hello this is dog')\n        .buffer(false)\n        .end((error, res) => {\n          assert.ifError(error);\n          assert.equal(null, res.text);\n          assert.deepEqual(res.body, {});\n          let str = '';\n          res.setEncoding('utf8');\n          res.on('data', (chunk) => {\n            str += chunk;\n          });\n          res.on('end', () => {\n            assert.equal(str, 'hello this is dog');\n            done();\n          });\n        });\n    });\n\n    it(\"should take precedence over request.buffer['someMimeType'] = true\", (done) => {\n      const type = 'application/foobar';\n      const send = 'hello this is a dog';\n      request.buffer[type] = true;\n      request\n        .post(`${base}/echo`)\n        .type(type)\n        .send(send)\n        .buffer(false)\n        .end((error, res) => {\n          delete request.buffer[type];\n          assert.ifError(error);\n          assert.equal(null, res.text);\n          assert.equal(res.type, type);\n          assert.equal(res.buffered, false);\n          assert.deepEqual(res.body, {});\n          let str = '';\n          res.setEncoding('utf8');\n          res.on('data', (chunk) => {\n            str += chunk;\n          });\n          res.on('end', () => {\n            assert.equal(str, send);\n            done();\n          });\n        });\n    });\n  });\n\n  describe('.withCredentials()', () => {\n    it('should not throw an error when using the client-side \"withCredentials\" method', (done) => {\n      request\n        .get(`${base}/custom`)\n        .withCredentials()\n        .end((error, res) => {\n          assert.ifError(error);\n          done();\n        });\n    });\n  });\n\n  describe('.agent()', () => {\n    it('should return the defaut agent', (done) => {\n      const agent = request.post(`${base}/echo`).agent();\n      assert.equal(agent, false);\n      done();\n    });\n  });\n\n  describe('.agent(undefined)', () => {\n    it('should set an agent to undefined and ensure it is chainable', (done) => {\n      const request_ = request.get(`${base}/echo`);\n      const returnValue = request_.agent(undefined);\n      assert.equal(returnValue, request_);\n      assert.strictEqual(request_.agent(), undefined);\n      done();\n    });\n  });\n\n  describe('.agent(new http.Agent())', () => {\n    it('should set passed agent', (done) => {\n      const http = require('http');\n      const request_ = request.get(`${base}/echo`);\n      const agent = new http.Agent();\n      const returnValue = request_.agent(agent);\n      assert.equal(returnValue, request_);\n      assert.equal(request_.agent(), agent);\n      done();\n    });\n  });\n\n  describe('with a content type other than application/json or text/*', () => {\n    it('should still use buffering', () => {\n      return request\n        .post(`${base}/echo`)\n        .type('application/x-dog')\n        .send('hello this is dog')\n        .then((res) => {\n          assert.equal(res.text, null);\n          assert.equal(res.body.toString(), 'hello this is dog');\n          assert.equal(res.buffered, true);\n        });\n    });\n  });\n\n  describe('content-length', () => {\n    it('should be set to the byte length of a non-buffer object', (done) => {\n      const decoder = new StringDecoder('utf8');\n      let img = fs.readFileSync(`${__dirname}/fixtures/test.png`);\n      img = decoder.write(img);\n      request\n        .post(`${base}/echo`)\n        .type('application/x-image')\n        .send(img)\n        .buffer(false)\n        .end((error, res) => {\n          assert.ifError(error);\n          assert.equal(res.buffered, false);\n          assert.equal(res.header['content-length'], Buffer.byteLength(img));\n          done();\n        });\n    });\n\n    it('should be set to the length of a buffer object', (done) => {\n      const img = fs.readFileSync(`${__dirname}/fixtures/test.png`);\n      request\n        .post(`${base}/echo`)\n        .type('application/x-image')\n        .send(img)\n        .buffer(true)\n        .end((error, res) => {\n          assert.ifError(error);\n          assert(res.buffered);\n          assert.equal(res.header['content-length'], img.length);\n          done();\n        });\n    });\n  });\n\n  if (doesntWorkInHttp2)\n    it('should send body with .get().send()', (next) => {\n      request\n        .get(`${base}/echo`)\n        .set('Content-Type', 'text/plain')\n        .send('wahoo')\n        .end((error, res) => {\n          try {\n            assert.equal(res.text, 'wahoo');\n            next();\n          } catch (err) {\n            next(err);\n          }\n        });\n    });\n});\n"
  },
  {
    "path": "test/node/buffers.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe(\"req.buffer['someMimeType']\", () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should respect that agent.buffer(true) takes precedent', (done) => {\n    const agent = request.agent();\n    agent.buffer(true);\n    const type = 'application/somerandomtype';\n    const send = 'somerandomtext';\n    request.buffer[type] = false;\n    agent\n      .post(`${base}/echo`)\n      .type(type)\n      .send(send)\n      .end((error, res) => {\n        delete request.buffer[type];\n        assert.ifError(error);\n        assert.equal(res.type, type);\n        assert.equal(send, res.text);\n        assert(res.buffered);\n        done();\n      });\n  });\n\n  it('should respect that agent.buffer(false) takes precedent', (done) => {\n    const agent = request.agent();\n    agent.buffer(false);\n    const type = 'application/barrr';\n    const send = 'some random text2';\n    request.buffer[type] = true;\n    agent\n      .post(`${base}/echo`)\n      .type(type)\n      .send(send)\n      .end((error, res) => {\n        delete request.buffer[type];\n        assert.ifError(error);\n        assert.equal(null, res.text);\n        assert.equal(res.type, type);\n        assert(!res.buffered);\n        res.body.should.eql({});\n        let buf = '';\n        res.setEncoding('utf8');\n        res.on('data', (chunk) => {\n          buf += chunk;\n        });\n        res.on('end', () => {\n          buf.should.equal(send);\n          done();\n        });\n      });\n  });\n\n  it('should disable buffering for that mimetype when false', (done) => {\n    const type = 'application/bar';\n    const send = 'some random text';\n    request.buffer[type] = false;\n    request\n      .post(`${base}/echo`)\n      .type(type)\n      .send(send)\n      .end((error, res) => {\n        delete request.buffer[type];\n        assert.ifError(error);\n        assert.equal(null, res.text);\n        assert.equal(res.type, type);\n        assert(!res.buffered);\n        res.body.should.eql({});\n        let buf = '';\n        res.setEncoding('utf8');\n        res.on('data', (chunk) => {\n          buf += chunk;\n        });\n        res.on('end', () => {\n          buf.should.equal(send);\n          done();\n        });\n      });\n  });\n  it('should enable buffering for that mimetype when true', (done) => {\n    const type = 'application/baz';\n    const send = 'woooo';\n    request.buffer[type] = true;\n    request\n      .post(`${base}/echo`)\n      .type(type)\n      .send(send)\n      .end((error, res) => {\n        delete request.buffer[type];\n        assert.ifError(error);\n        assert.equal(res.type, type);\n        assert.equal(send, res.text);\n        assert(res.buffered);\n        done();\n      });\n  });\n  it('should fallback to default handling for that mimetype when undefined', () => {\n    const type = 'application/bazzz';\n    const send = 'woooooo';\n    return request\n      .post(`${base}/echo`)\n      .type(type)\n      .send(send)\n      .then((res) => {\n        assert.equal(res.type, type);\n        assert.equal(send, res.body.toString());\n        assert(res.buffered);\n      });\n  });\n});\n"
  },
  {
    "path": "test/node/exports.js",
    "content": "'use strict';\nconst request = require('../support/client');\n\ndescribe('exports', () => {\n  it('should expose .protocols', () => {\n    Object.keys(request.protocols).should.eql(['http:', 'https:', 'http2:']);\n  });\n\n  it('should expose .serialize', () => {\n    Object.keys(request.serialize).should.eql([\n      'application/x-www-form-urlencoded',\n      'application/json'\n    ]);\n  });\n\n  it('should expose .parse', () => {\n    Object.keys(request.parse).should.eql([\n      'application/x-www-form-urlencoded',\n      'application/json',\n      'text',\n      'application/json-seq',\n      'application/octet-stream',\n      'application/pdf',\n      'image'\n    ]);\n  });\n\n  it('should export .buffer', () => {\n    Object.keys(request.buffer).should.eql([]);\n  });\n});\n"
  },
  {
    "path": "test/node/fixtures/ca.cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICljCCAX4CCQDnGz3+qH/zGzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJD\nQTAeFw0xODEyMDIxNjIyMThaFw0zMjA4MTAxNjIyMThaMA0xCzAJBgNVBAMMAkNB\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtgUDcB7R94A22I0D8Iba\nc000ZBINtvnyvoPP5U2hRsxI9tcW/LLm0GhzM5XJJNQ0jSv0ixIFKomtFBSjKMq/\nNH156SqKqyDGU1fPnGjzcJulxceODIokAqNCbZ7Bys6nqUdilNfLQ4bBBWYsEUWT\nvgbUeDRHvQGycou/pLpYGLCJ4tpc4n6ybox1uPi0qlvFI7aWvQFjOxxR0VeRixXf\nqXjVCDIr9OJIWiXLrJYDlYqG2gRF/yTDZ4qmQxbZzJ6AXMpaRUiHUO0FHu7baEux\nylIc0KVcAmYMGdhFlmDrMNRsmnADKPX9DIMh92XWyE10oNK50I1rIhpvN4XfQx6E\nUwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCIXj1vfTVRB4ea/udjazPHaLAeocbg\nd8babbDItOm1ApAoUhNuxPVxyISSFrowCVlaWxB+1ztfeUAB/Axfj0mbXk1hgo2D\n4+rft8hOtdg91bU+gHPd/7QGkpPIs5PC+TsnVj0mNqZ5o8qZsLhgoXp3Dl5yMhEs\nsRegLkmBQHzEsKFU2cSxVD7BXXGLDJxcoR4friGOXdIZeYwqHTZsuR3O7JOVbLew\ndURqD70jPuf9v1tBnkJPbUECMlL7BCw6ZQtglSvjPP/waWir9TMsDk+xwPK8NPbv\nDGi+w++cImBbxcnIMBTk4XtlFcOnCCAYUfkaxZMw2jNhYbjiEZOGUG8m\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/node/fixtures/ca.key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAtgUDcB7R94A22I0D8Ibac000ZBINtvnyvoPP5U2hRsxI9tcW\n/LLm0GhzM5XJJNQ0jSv0ixIFKomtFBSjKMq/NH156SqKqyDGU1fPnGjzcJulxceO\nDIokAqNCbZ7Bys6nqUdilNfLQ4bBBWYsEUWTvgbUeDRHvQGycou/pLpYGLCJ4tpc\n4n6ybox1uPi0qlvFI7aWvQFjOxxR0VeRixXfqXjVCDIr9OJIWiXLrJYDlYqG2gRF\n/yTDZ4qmQxbZzJ6AXMpaRUiHUO0FHu7baEuxylIc0KVcAmYMGdhFlmDrMNRsmnAD\nKPX9DIMh92XWyE10oNK50I1rIhpvN4XfQx6EUwIDAQABAoIBAAomAWkQ7tgD2Ar+\n4cdZXXisR02FDCq1iOlCZCb+yw0teqv4lhmEyAW6rSGlKk/ZXQy59KqEWLFkd7f0\n5pvxofOFQ3TSoGSmMSiYbsTjvR78LqP2Wl8snJFhFOUTwu5R01tG1aJC3dxn+P8a\nET7tSC2CJ/qDv7Q0EgT88bR3h03pAc2PJAGWJ2QwutAwV+6Ilyt3hcz29f7JGQac\nDa0jY/7RIpvZL20gsecb/6Q0a50VEbkuJ+OF5QyIQNT9qtfvsqavtsjHgBWs3iFG\nyKaDCey4X7D+NsyJBKNCuDqWXzq/4+mQ3atBIvYq2mcIpIbaku7TEWHvpxfzsT/F\nSzLncMECgYEA4qR1GU38UxZ/8x6Cc4Z3DKUuCLBqvv69IHPcfSkhrtTeApdsv14U\nKE66/Z3g4FXeV018GYUzGODfjBt4VnDCutz9tmiHFH+T2zDpgC7hvODC8rJ+D21b\nG3Q5eyA+XRao1XHjc2UD/Ev6iJPjgCT23Lur2bhAqCKkV4g2EAWCgyMCgYEAzZjY\n5M7Jw+0g5b6ILnFX66JbESrw87OtiIpiQh5XUQssKsmfONzbXUp6ch/MRTFVHVDZ\nXmG35Xyg6vy1FYg9HTALl1tnkh9UIhKrH7jx+6euhc0HyWCCqSp/3CpJqVjdoxtS\nvtZigSaxwTDaOYc8r54cWhHIIrpTrcqY4mxdZRECgYBpGWhv9pkXEqz82d4Wonlc\ndNDXGLA3p7uea/wIUmWbRH07aGr2hzMDyhaue2MHxOoZRAZTc1BRrh4cQ7TXKO00\naDyDNQ/G8q5nC9SMK7FkvDnK//izQLvqDEiHj1k8I8DhUjHulh52BenFIgdyqjGM\nBL9ZdDcPgRkCuliPr25pTwKBgG8rf9QxEJ51oT05Sk+6j+zk7FMbIhDUjjfvg/P2\njgZPgUFdpk/L9H28YPtGwGCFrV1dszu6oQJg4m5N2OjcsxcOPKZKEXXMpOSLraZI\njegiolbNJ7G3Es/AIET/RLdiSu4APzzblYX6U1GARe+ndaQMXY5CYTKOB+NIUmTU\nbafRAoGAV8PptnjWf9ehJvt96Rz0FdfpN7leqdweK2JrGZwJQ9BRcKwUO758lmyN\nnC62Sd0mwHivxRqI6e2u7OSvGj9e7iLnHMl4qYie7VvsWAWmztH2ntEI0iWA3V3N\nM3T9+sz+nslfhWKgIA80EqOWB1AF0EmbmmqK0igWEbYynAr6v0Q=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/node/fixtures/ca.srl",
    "content": "B23299143E26EFC5\n"
  },
  {
    "path": "test/node/fixtures/cert.csr",
    "content": "-----BEGIN CERTIFICATE REQUEST-----\nMIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEAsjNYMUk1HzBLM4fL/8c6Z86X/b13V1bMXrrcV28w\njmvQv4lADlghZGt/zbinyvZrASp8v1btR9gLaNTdrxxnz5FWu1bY947ljgadudh0\nSTLNs4jWI2wcjgguA8B2rDtvap0bn9JkpjQGcFuqEdJRlr26OwsC5SNCtFxQmTrb\nsneFMWK3JsL1riCrV9Cw0L3joki/YKYTTwRZJ2TXrrHvOLQCIUacwCU4oJg19D0F\nKU/rDtdUFFojnTio0RFU4/OpjxKzwqjSJE80nPSRHAqXtSgmphrRk4ZVeTxKEGKC\noAt/RBwqvxPFjNlbr1EWY9S7SpFu06V35jXJYD9CWD/WcQIDAQABoAAwDQYJKoZI\nhvcNAQELBQADggEBACia2hDAe1YqzVn/P2KSX+/9yDrjOhU20hKF1CTZr3Zfjep9\nR86ldz1aFc2N2yqDjUYpj0+DODEXlEfNaYcD2nn93qgy/gAmfQUvCejBh6vsGiIW\nqc41lzEGHa9/ErxQ7yvETeuY8OozjDAoUs5NUbFL6OmwJFqX9VzLbQ8uQxNU3z3l\nAKVkWBWIubqpSa8tDn/+wf8vW/xtOCZ/Zd5YBQdTCwb5BdS3vpBkwpJbPBvR97Mc\n2d+2a5qyNqZdb1CuATS2MJC35zp62FErhcnnVqtaAcaE/C/in1OO3wLJvXa5/LKp\n1riBUJLHscGbIhe+KjlLoosXuOcUNvBkNbt8MFQ=\n-----END CERTIFICATE REQUEST-----\n"
  },
  {
    "path": "test/node/fixtures/cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICnTCCAYUCCQCyMpkUPibvxTANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJD\nQTAeFw0xODEyMDIxNjIzNTBaFw0zMjA4MTAxNjIzNTBaMBQxEjAQBgNVBAMMCWxv\nY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALIzWDFJNR8w\nSzOHy//HOmfOl/29d1dWzF663FdvMI5r0L+JQA5YIWRrf824p8r2awEqfL9W7UfY\nC2jU3a8cZ8+RVrtW2PeO5Y4GnbnYdEkyzbOI1iNsHI4ILgPAdqw7b2qdG5/SZKY0\nBnBbqhHSUZa9ujsLAuUjQrRcUJk627J3hTFitybC9a4gq1fQsNC946JIv2CmE08E\nWSdk166x7zi0AiFGnMAlOKCYNfQ9BSlP6w7XVBRaI504qNERVOPzqY8Ss8Ko0iRP\nNJz0kRwKl7UoJqYa0ZOGVXk8ShBigqALf0QcKr8TxYzZW69RFmPUu0qRbtOld+Y1\nyWA/Qlg/1nECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAWYlRC8e5flZED/JDP0VG\naNENVwv0bFbbzp1urgQeq1TVBDHGKuMJM9klVMBQiMT9q+nPjEgfynSiLVuY7FWs\nyD/hFjQMLV2cz7tdBY6l+IV1sAtBdX3ZRmmzttaAs4xmFXCLXdTm4KJ5bPcRnRLA\nklMKOsvNY90mRteXvhQy04J2TJVpIld05+yjnYVWoODyX9A/Xda+33qjZECLTnj4\nc5L3mamPZEo4nwY+329d7dNvEu+ETp4UzwkzwPFHSGLD01YEJIu83TTi1WDBZygz\ndxPUkLKYzRkpYVp3hbZsvkCQVtruY/e6DADZTKAlhL41V6VdH35Es0uw7JrbPf7z\njQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/node/fixtures/key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsjNYMUk1HzBLM4fL/8c6Z86X/b13V1bMXrrcV28wjmvQv4lA\nDlghZGt/zbinyvZrASp8v1btR9gLaNTdrxxnz5FWu1bY947ljgadudh0STLNs4jW\nI2wcjgguA8B2rDtvap0bn9JkpjQGcFuqEdJRlr26OwsC5SNCtFxQmTrbsneFMWK3\nJsL1riCrV9Cw0L3joki/YKYTTwRZJ2TXrrHvOLQCIUacwCU4oJg19D0FKU/rDtdU\nFFojnTio0RFU4/OpjxKzwqjSJE80nPSRHAqXtSgmphrRk4ZVeTxKEGKCoAt/RBwq\nvxPFjNlbr1EWY9S7SpFu06V35jXJYD9CWD/WcQIDAQABAoIBAGvpieO2yHONpEyd\nVJ0dAbJxOjuPa+C5EGPhVqOgEtB8W9pRfDfziK0uKCPlSb8wAFahaw/XzTMvkqE2\nHtT3J6pcAiDKk/M+VqbuPL+ZY7ocCNNK7xpeUuBz9aGSAIuGJo9yepMLLqYzZR7P\nc6r9KSlW1ZsBrQwjkTZ1nN1d9kMY+SBpW4PY3lfA69dfPDQ6hsbg+7e37MkP2ygP\nLL3H+oljAZJiRSWu7+F2FwTUkNom9va6aKr2FuUgr7pd9PnBoDIEyEWu1sF6nJ85\nvVbGRCCkvub+D55U6Q7PsscOY8lc6Z3JaQA7sv8alSHR+q9AOEvkc4uc2V4J9LOa\nZlZzOD0CgYEA1nYxoHe1hNIKHRjY38wSbyfPAKZ9tzrPLq44JBe+9MoMN+pOLA9N\nSVorLz9OHl8A4gCMeLgXrX06ECHor1dbC90k+jiU0taOdcADs0BwAbWrgMyiOsjJ\nRbwTRUTsAuLLldTBf4sFysCyG0SYCqFL7hJJh2HJKOg428V8b0sfaV8CgYEA1Lcw\neEc11R80Huv5yV8WeYu+uqBo38P1qoC+zlpa7PRw9GX4Ovi20hwkqWNlOyho0TJa\nx9HLl87WW/p7pjCM6kcBdHOn0eqHgoUYknYbsVyK0o2P5ajMldOkRu03lqjNuB9/\nQ4BYp8Sqwyv/aTGMNDa/TlX8S+3Lk8WIkhBPQi8CgYEAm6xoEadTp/ofRUfIBYvI\nxc8Lv9ka4GpcAfKM5gYmouIXRG9cFzd0To6ZUk6NkhY8OdFUJjzbUx/XieZTVRQA\nDviT4t43iWQdPPQIu5FGvLb2qyPfjvQ4xdnj0yBYgS/HwBcT7lUn+yktIAYGp5C1\n4TZ9ETy2HG+U9lLAJLlPL9kCgYA+N6rMs39ya+MR3FG+bbqkKJTL/5lNQgL8MRYe\nQ11vC3xyb9TwYskOob6zcOguKn6mGcVlxt5287/NPXGnRXIiIEyzpBSFGMU0DvwF\n8tfcw8WzGkbplLrqY/Ib8Myem5c4cLYHp2XHBIYx+g+F1EE/EHhaUFowV0iBW3i7\nyFt2bwKBgG1EycLZ5EMXtitMNdPigRR7UJnNAPSreYrSrFSKYrR6tAHhsAf/uiK/\nWf3hXJvIwRrJOJc29juCi3r8i5xhcoRN7kdd1dOXzEX4azn6PCi27b7wDN20w/Wv\nQeeV1QQ0x1ok7AHWLBEZLuYFaded0UnGrDwtwKQ9wg8oH98n8jkR\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/node/fixtures/user.html",
    "content": "<h1>name</h1>"
  },
  {
    "path": "test/node/fixtures/user.json",
    "content": "{\"name\":\"tobi\"}"
  },
  {
    "path": "test/node/fixtures/user.txt",
    "content": "Tobi"
  },
  {
    "path": "test/node/flags.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('flags', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('with 4xx response', () => {\n    it('should set res.error and res.clientError', (done) => {\n      request.get(`${base}/notfound`).end((error, res) => {\n        assert(error);\n        assert(!res.ok, 'response should not be ok');\n        assert(res.error, 'response should be an error');\n        assert(res.clientError, 'response should be a client error');\n        assert(!res.serverError, 'response should not be a server error');\n        done();\n      });\n    });\n  });\n\n  describe('with 5xx response', () => {\n    it('should set res.error and res.serverError', (done) => {\n      request.get(`${base}/error`).end((error, res) => {\n        assert(error);\n        assert(!res.ok, 'response should not be ok');\n        assert(!res.notFound, 'response should not be notFound');\n        assert(res.error, 'response should be an error');\n        assert(!res.clientError, 'response should not be a client error');\n        assert(res.serverError, 'response should be a server error');\n        done();\n      });\n    });\n  });\n\n  describe('with 404 Not Found', () => {\n    it('should res.notFound', (done) => {\n      request.get(`${base}/notfound`).end((error, res) => {\n        assert(error);\n        assert(res.notFound, 'response should be .notFound');\n        done();\n      });\n    });\n  });\n\n  describe('with 400 Bad Request', () => {\n    it('should set req.badRequest', (done) => {\n      request.get(`${base}/bad-request`).end((error, res) => {\n        assert(error);\n        assert(res.badRequest, 'response should be .badRequest');\n        done();\n      });\n    });\n  });\n\n  describe('with 401 Bad Request', () => {\n    it('should set res.unauthorized', (done) => {\n      request.get(`${base}/unauthorized`).end((error, res) => {\n        assert(error);\n        assert(res.unauthorized, 'response should be .unauthorized');\n        done();\n      });\n    });\n  });\n\n  describe('with 406 Not Acceptable', () => {\n    it('should set res.notAcceptable', (done) => {\n      request.get(`${base}/not-acceptable`).end((error, res) => {\n        assert(error);\n        assert(res.notAcceptable, 'response should be .notAcceptable');\n        done();\n      });\n    });\n  });\n\n  describe('with 204 No Content', () => {\n    it('should set res.noContent', (done) => {\n      request.get(`${base}/no-content`).end((error, res) => {\n        assert(!error);\n        assert(res.noContent, 'response should be .noContent');\n        done();\n      });\n    });\n  });\n\n  describe('with 201 Created', () => {\n    it('should set res.created', (done) => {\n      request.post(`${base}/created`).end((error, res) => {\n        assert(!error);\n        assert(res.created, 'response should be .created');\n        done();\n      });\n    });\n  });\n\n  describe('with 422 Unprocessable Entity', () => {\n    it('should set res.unprocessableEntity', (done) => {\n      request.post(`${base}/unprocessable-entity`).end((error, res) => {\n        assert(error);\n        assert(\n          res.unprocessableEntity,\n          'response should be .unprocessableEntity'\n        );\n\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/form.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('Merging objects', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it(\"Don't mix Buffer and JSON\", () => {\n    assert.throws(() => {\n      request\n        .post('/echo')\n        .send(Buffer.from('some buffer'))\n        .send({ allowed: false });\n    });\n  });\n});\n\ndescribe('req.send(String)', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should default to \"form\"', (done) => {\n    request\n      .post(`${base}/echo`)\n      .send('user[name]=tj')\n      .send('user[email]=tj@vision-media.ca')\n      .end((error, res) => {\n        res.header['content-type'].should.equal(\n          'application/x-www-form-urlencoded'\n        );\n        res.body.should.eql({\n          user: { name: 'tj', email: 'tj@vision-media.ca' }\n        });\n        done();\n      });\n  });\n});\n\ndescribe('res.body', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('application/x-www-form-urlencoded', () => {\n    it('should parse the body', (done) => {\n      request.get(`${base}/form-data`).end((error, res) => {\n        res.text.should.equal('pet[name]=manny');\n        res.body.should.eql({ pet: { name: 'manny' } });\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/http2.js",
    "content": "'use strict';\nif (!process.env.HTTP2_TEST) {\n  return;\n}\n\nconst assert = require('assert');\nconst request = require('../..');\nconst getSetup = require('../support/setup');\n\ndescribe('request.get().http2()', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should preserve the encoding of the url', (done) => {\n    request\n      .get(`${base}/url?a=(b%29`)\n      .http2()\n      .end((error, res) => {\n        assert.equal('/url?a=(b%29', res.text);\n        done();\n      });\n  });\n\n  it('should format the url', () =>\n    request\n      .get(new URL(`${base}/login`))\n      .http2()\n      .then((res) => {\n        assert(res.ok);\n      }));\n\n  it.skip('should default to http', () =>\n    request\n      .get('localhost:5000/login')\n      .http2()\n      .then((res) => {\n        assert.equal(res.status, 200);\n      }));\n});\n"
  },
  {
    "path": "test/node/https.js",
    "content": "'use strict';\n\nconst assert = require('assert');\n\nconst https = require('https');\nconst fs = require('fs');\nconst express = require('../support/express');\nconst request = require('../support/client');\n\nconst app = express();\n\nconst ca = fs.readFileSync(`${__dirname}/fixtures/ca.cert.pem`);\nconst key = fs.readFileSync(`${__dirname}/fixtures/key.pem`);\nconst pfx = fs.readFileSync(`${__dirname}/fixtures/cert.pfx`);\nconst cert = fs.readFileSync(`${__dirname}/fixtures/cert.pem`);\nconst passpfx = fs.readFileSync(`${__dirname}/fixtures/passcert.pfx`);\n\n/*\n\nopenssl genrsa -out ca.key.pem 2048\nopenssl req -x509 -new -nodes -key ca.key.pem -sha256 -days 5000 -out ca.cert.pem # specify CN = CA\n\nopenssl genrsa -out key.pem 2048\nopenssl req -new -key key.pem -out cert.csr # specify CN = localhost\n\nopenssl x509 -req -in cert.csr -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -out cert.pem -days 5000 -sha256\nopenssl pkcs12 -export -in cert.pem -inkey key.pem -out cert.pfx # empty password\n\nopenssl pkcs12 -export -in cert.pem -inkey key.pem -out passcert.pfx # password test\n\n */\nlet http2;\nif (process.env.HTTP2_TEST) {\n  http2 = require('http2');\n}\n\nlet server;\n\napp.get('/', (request_, res) => {\n  res.send('Safe and secure!');\n});\n\n// WARNING: this .listen() boilerplate is slightly different from most tests\n// due to HTTPS. Do not copy/paste without examination.\nconst base = 'https://localhost';\nlet testEndpoint;\n\ndescribe('https', () => {\n  describe('certificate authority', () => {\n    before(function listen(done) {\n      server = process.env.HTTP2_TEST\n        ? http2.createSecureServer(\n            {\n              key,\n              cert\n            },\n            app\n          )\n        : https.createServer(\n            {\n              key,\n              cert\n            },\n            app\n          );\n\n      server.listen(0, function listening() {\n        testEndpoint = `${base}:${server.address().port}`;\n        done();\n      });\n    });\n\n    after(() => {\n      if (server) server.close();\n    });\n\n    describe('request', () => {\n      it('should give a good response', (done) => {\n        request\n          .get(testEndpoint)\n          .ca(ca)\n          .end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n      });\n\n      it('should reject unauthorized response', () => {\n        return request\n          .get(testEndpoint)\n          .trustLocalhost(false)\n          .then(\n            () => {\n              throw new Error('Allows MITM');\n            },\n            () => {}\n          );\n      });\n\n      it('should not reject unauthorized response', () => {\n        return request\n          .get(testEndpoint)\n          .disableTLSCerts()\n          .then(({ status }) => {\n            assert.strictEqual(status, 200);\n          });\n      });\n\n      it('should trust localhost unauthorized response', () => {\n        return request.get(testEndpoint).trustLocalhost(true);\n      });\n\n      it('should trust overriden localhost unauthorized response', () => {\n        return request\n          .get(`https://example.com:${server.address().port}`)\n          .connect('127.0.0.1')\n          .trustLocalhost();\n      });\n    });\n\n    describe('.agent', () => {\n      it('should be able to make multiple requests without redefining the certificate', (done) => {\n        const agent = request.agent({ ca });\n        agent.get(testEndpoint).end((error, res) => {\n          assert.ifError(error);\n          assert(res.ok);\n          assert.strictEqual('Safe and secure!', res.text);\n          agent.get(new URL(testEndpoint)).end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  describe.skip('client certificates', () => {\n    before(function listen(done) {\n      server = process.env.HTTP2_TEST\n        ? http2.createSecureServer(\n            {\n              ca,\n              key,\n              cert,\n              requestCert: true,\n              rejectUnauthorized: true\n            },\n            app\n          )\n        : https.createServer(\n            {\n              ca,\n              key,\n              cert,\n              requestCert: true,\n              rejectUnauthorized: true\n            },\n            app\n          );\n\n      server.listen(0, function listening() {\n        testEndpoint = `${base}:${server.address().port}`;\n        done();\n      });\n    });\n\n    after(() => {\n      if (server) server.close();\n    });\n\n    describe('request', () => {\n      it('should give a good response with client certificates and CA', (done) => {\n        request\n          .get(testEndpoint)\n          .ca(ca)\n          .key(key)\n          .cert(cert)\n          .end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n      });\n      it('should give a good response with client pfx', (done) => {\n        request\n          .get(testEndpoint)\n          .pfx(pfx)\n          .end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n      });\n      it('should give a good response with client pfx with passphrase', (done) => {\n        request\n          .get(testEndpoint)\n          .pfx({\n            pfx: passpfx,\n            passphrase: 'test'\n          })\n          .end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n      });\n    });\n\n    describe('.agent', () => {\n      it('should be able to make multiple requests without redefining the certificates', (done) => {\n        const agent = request.agent({ ca, key, cert });\n        agent.get(testEndpoint).end((error, res) => {\n          assert.ifError(error);\n          assert(res.ok);\n          assert.strictEqual('Safe and secure!', res.text);\n          agent.get(new URL(testEndpoint)).end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n        });\n      });\n      it('should be able to make multiple requests without redefining pfx', (done) => {\n        const agent = request.agent({ pfx });\n        agent.get(testEndpoint).end((error, res) => {\n          assert.ifError(error);\n          assert(res.ok);\n          assert.strictEqual('Safe and secure!', res.text);\n          agent.get(new URL(testEndpoint)).end((error, res) => {\n            assert.ifError(error);\n            assert(res.ok);\n            assert.strictEqual('Safe and secure!', res.text);\n            done();\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/image.js",
    "content": "'use strict';\n\nconst fs = require('fs');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\nconst img = fs.readFileSync(`${__dirname}/fixtures/test.png`);\n\ndescribe('res.body', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('image/png', () => {\n    it('should parse the body', (done) => {\n      request.get(`${base}/image`).end((error, res) => {\n        res.type.should.equal('image/png');\n        Buffer.isBuffer(res.body).should.be.true();\n        (res.body.length - img.length).should.equal(0);\n        done();\n      });\n    });\n  });\n  describe('application/octet-stream', () => {\n    it('should parse the body', (done) => {\n      request\n        .get(`${base}/image-as-octets`)\n        .buffer(true) // that's tech debt :(\n        .end((error, res) => {\n          res.type.should.equal('application/octet-stream');\n          Buffer.isBuffer(res.body).should.be.true();\n          (res.body.length - img.length).should.equal(0);\n          done();\n        });\n    });\n  });\n  describe('application/octet-stream', () => {\n    it('should parse the body (using responseType)', (done) => {\n      request\n        .get(`${base}/image-as-octets`)\n        .responseType('blob')\n        .end((error, res) => {\n          res.type.should.equal('application/octet-stream');\n          Buffer.isBuffer(res.body).should.be.true();\n          (res.body.length - img.length).should.equal(0);\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/incoming-multipart.js",
    "content": "// var request = require('../support/client')\n//   , express = require('express')\n//   , assert = require('assert')\n//   , app = express()\n//   , fs = require('fs');\n\n// app.get('/', function(req, res){\n//   res.set('Content-Type', 'multipart/form-data; boundary=awesome');\n//   // res.write('\\r\\n'); TODO: formidable bug\n//   res.write('--awesome\\r\\n');\n//   res.write('Content-Disposition: attachment; name=\"image\"; filename=\"something.png\"\\r\\n');\n//   res.write('Content-Type: image/png\\r\\n');\n//   res.write('\\r\\n');\n//   res.write('some data');\n//   res.write('\\r\\n--awesome\\r\\n');\n//   res.write('Content-Disposition: form-data; name=\"name\"\\r\\n');\n//   res.write('Content-Type: text/plain\\r\\n');\n//   res.write('\\r\\n');\n//   res.write('tobi');\n//   res.write('\\r\\n--awesome--');\n//   setTimeout(function(){ // TODO: lolnode...\n//     res.end();\n//   }, 1000);\n// });\n\n// var base = 'http://localhost'\n// var server;\n// before(function listen(done) {\n//   server = app.listen(0, function listening() {\n//     base += ':' + server.address().port;\n//     done();\n//   });\n// });\n\n// describe('request multipart/form-data', function(){\n//   describe('req.body', function(){\n//     it('should be populated with fields', function(done){\n//       request.get(base, function(err, res){\n//         if (err) return done(err);\n//         res.status.should.equal(200);\n//         res.body.should.eql({ name: 'tobi' });\n//         res.files.image.name.should.equal('something.png');\n//         res.files.image.type.should.equal('image/png');\n//         assert.equal(null, res.text, 'res.text should be empty for multipart');\n//         done();\n//       });\n//     })\n//   })\n// })\n"
  },
  {
    "path": "test/node/inflate.js",
    "content": "'use strict';\nrequire('should');\nrequire('should-http');\n\nconst assert = require('assert');\nconst zlib = require('zlib');\nlet http = require('http');\nconst getPort = require('get-port');\nconst express = require('../support/express');\nconst request = require('../support/client');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\nconst app = express();\nconst subject = 'some long long long long string';\n\nlet base = 'http://localhost';\nlet server;\n\nbefore(function listen(done) {\n  server = http.createServer(app);\n\n  getPort().then((port) => {\n    server = server.listen(port, function listening() {\n      base += `:${server.address().port}`;\n      done();\n    });\n  });\n});\n\napp.get('/binary', (request_, res) => {\n  zlib.deflate(subject, (error, buf) => {\n    res.set('Content-Encoding', 'gzip');\n    res.send(buf);\n  });\n});\n\napp.get('/binary-brotli', (request_, res) => {\n  zlib.brotliCompress(subject, (error, buf) => {\n    res.set('Content-Encoding', 'br');\n    res.send(buf);\n  });\n});\n\napp.get('/corrupt', (request_, res) => {\n  res.set('Content-Encoding', 'gzip');\n  res.send('blah');\n});\n\napp.get('/corrupt-brotli', (request_, res) => {\n  res.set('Content-Encoding', 'br');\n  res.send('blah');\n});\n\napp.get('/nocontent', (request_, res, next) => {\n  res.statusCode = 204;\n  res.set('Content-Type', 'text/plain');\n  res.set('Content-Encoding', 'gzip');\n  res.send('');\n});\n\napp.get('/nocontent-brotli', (request_, res, next) => {\n  res.statusCode = 204;\n  res.set('Content-Type', 'text/plain');\n  res.set('Content-Encoding', 'br');\n  res.send('');\n});\n\napp.get('/', (request_, res, next) => {\n  zlib.deflate(subject, (error, buf) => {\n    res.set('Content-Type', 'text/plain');\n    res.set('Content-Encoding', 'gzip');\n    res.send(buf);\n  });\n});\n\napp.get('/junk', (request_, res) => {\n  zlib.deflate(subject, (error, buf) => {\n    res.set('Content-Type', 'text/plain');\n    res.set('Content-Encoding', 'gzip');\n    res.write(buf);\n    res.end(' 0 junk');\n  });\n});\n\napp.get('/junk-brotli', (request_, res) => {\n  zlib.brotliCompress(subject, (error, buf) => {\n    res.set('Content-Type', 'text/plain');\n    res.set('Content-Encoding', 'br');\n    res.write(buf);\n    res.end(' 0 junk');\n  });\n});\n\napp.get('/chopped', (request_, res) => {\n  zlib.deflate(`${subject}123456`, (error, buf) => {\n    res.set('Content-Type', 'text/plain');\n    res.set('Content-Encoding', 'gzip');\n    res.send(buf.slice(0, -1));\n  });\n});\n\napp.get('/chopped-brotli', (request_, res) => {\n  zlib.brotliCompress(`${subject}123456`, (error, buf) => {\n    res.set('Content-Type', 'text/plain');\n    res.set('Content-Encoding', 'br');\n    res.send(buf.slice(0, -1));\n  });\n});\n\ndescribe('zlib', () => {\n  it('should deflate the content', (done) => {\n    request.get(base).end((error, res) => {\n      res.should.have.status(200);\n      res.text.should.equal(subject);\n      res.headers['content-length'].should.be.below(subject.length);\n      done();\n    });\n  });\n\n  it('should protect from zip bombs', (done) => {\n    request\n      .get(base)\n      .buffer(true)\n      .maxResponseSize(1)\n      .end((error, res) => {\n        try {\n          assert.equal('Maximum response size reached', error && error.message);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should ignore trailing junk', (done) => {\n    request.get(`${base}/junk`).end((error, res) => {\n      res.should.have.status(200);\n      res.text.should.equal(subject);\n      done();\n    });\n  });\n\n  it('should ignore trailing junk-brotli', (done) => {\n    request.get(`${base}/junk-brotli`).end((error, res) => {\n      res.should.have.status(200);\n      res.text.should.equal(subject);\n      done();\n    });\n  });\n\n  it('should ignore missing data', (done) => {\n    request.get(`${base}/chopped`).end((error, res) => {\n      assert.equal(undefined, error);\n      res.should.have.status(200);\n      res.text.should.startWith(subject);\n      done();\n    });\n  });\n\n  it('should ignore missing brotli data', (done) => {\n    request.get(`${base}/chopped-brotli`).end((error, res) => {\n      assert.equal(undefined, error);\n      res.should.have.status(200);\n      res.text.should.startWith(subject);\n      done();\n    });\n  });\n\n  it('should handle corrupted responses', (done) => {\n    request.get(`${base}/corrupt`).end((error, res) => {\n      assert(error, 'missing error');\n      assert(!res, 'response should not be defined');\n      done();\n    });\n  });\n\n  it('should handle brotli corrupted responses', (done) => {\n    request.get(`${base}/corrupt-brotli`).end((error, res) => {\n      res.text.should.equal('');\n      done();\n    });\n  });\n\n  it('should handle no content with gzip header', (done) => {\n    request.get(`${base}/nocontent`).end((error, res) => {\n      assert.ifError(error);\n      assert(res);\n      res.should.have.status(204);\n      res.text.should.equal('');\n      res.headers.should.not.have.property('content-length');\n      done();\n    });\n  });\n\n  it('should handle no content with gzip header', (done) => {\n    request.get(`${base}/nocontent-brotli`).end((error, res) => {\n      assert.ifError(error);\n      assert(res);\n      res.should.have.status(204);\n      res.text.should.equal('');\n      res.headers.should.not.have.property('content-length');\n      done();\n    });\n  });\n\n  describe('without encoding set', () => {\n    it('should buffer if asked', () => {\n      return request\n        .get(`${base}/binary`)\n        .buffer(true)\n        .then((res) => {\n          res.should.have.status(200);\n          assert(res.headers['content-length']);\n          assert(res.body.byteLength);\n          assert.equal(subject, res.body.toString());\n        });\n    });\n\n    it('should buffer Brotli if asked', () => {\n      return request\n        .get(`${base}/binary-brotli`)\n        .buffer(true)\n        .then((res) => {\n          res.should.have.status(200);\n          assert(res.headers['content-length']);\n          assert(res.body.byteLength);\n          assert.equal(subject, res.body.toString());\n        });\n    });\n\n    it('should emit buffers', (done) => {\n      request.get(`${base}/binary`).end((error, res) => {\n        res.should.have.status(200);\n        res.headers['content-length'].should.be.below(subject.length);\n\n        res.on('data', (chunk) => {\n          chunk.should.have.length(subject.length);\n        });\n\n        res.on('end', done);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/lookup.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst dns = require('dns');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\nlet base = null;\n\nfunction myLookup(hostname, options, callback) {\n  dns.lookup(hostname, options, callback);\n}\n\ndescribe('req.lookup()', () => {\n  before(async () => {\n    const setup = await getSetup();\n    base = setup.uri;\n  });\n  it('should set a custom lookup', (done) => {\n    const r = request.get(`${base}/ok`).lookup(myLookup);\n    assert(r.lookup() === myLookup);\n    r.then((res) => {\n      res.text.should.equal('ok');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/multipart.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\nconst should = require('should');\nconst getPort = require('get-port');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\nconst IS_WINDOWS = require('os').platform() === 'win32';\n\nfunction read(file) {\n  return fs.readFileSync(file, 'utf8');\n}\n\nfunction getFullPath(filename) {\n  if (!IS_WINDOWS) {\n    return filename;\n  }\n\n  const fullPath = path.join(__dirname, '../../', filename);\n  return fullPath;\n}\n\ndescribe('Multipart', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('#field(name, value)', () => {\n    it('should set a multipart field value', () => {\n      const request_ = request.post(`${base}/echo`);\n\n      request_.field('user[name]', 'tobi');\n      request_.field('user[age]', '2');\n      request_.field('user[species]', 'ferret');\n\n      return request_.then((res) => {\n        res.body['user[name]'].should.equal('tobi');\n        res.body['user[age]'].should.equal('2');\n        res.body['user[species]'].should.equal('ferret');\n      });\n    });\n\n    it('should work with file attachments', () => {\n      const request_ = request.post(`${base}/echo`);\n\n      request_.field('name', 'Tobi');\n      request_.attach('document', 'test/node/fixtures/user.html');\n      request_.field('species', 'ferret');\n\n      return request_.then((res) => {\n        res.body.name.should.equal('Tobi');\n        res.body.species.should.equal('ferret');\n\n        const html = res.files.document;\n        html.originalFilename.should.equal('user.html');\n        html.mimetype.should.equal('text/html');\n        read(html.filepath).should.equal('<h1>name</h1>');\n      });\n    });\n  });\n\n  describe('#attach(name, path)', () => {\n    it('should attach a file', () => {\n      const request_ = request.post(`${base}/echo`);\n\n      request_.attach('one', 'test/node/fixtures/user.html');\n      request_.attach('two', 'test/node/fixtures/user.json');\n      request_.attach('three', 'test/node/fixtures/user.txt');\n\n      return request_.then((res) => {\n        const html = res.files.one;\n        const json = res.files.two;\n        const text = res.files.three;\n\n        html.originalFilename.should.equal('user.html');\n        html.mimetype.should.equal('text/html');\n        read(html.filepath).should.equal('<h1>name</h1>');\n\n        json.originalFilename.should.equal('user.json');\n        json.mimetype.should.equal('application/json');\n        read(json.filepath).should.equal('{\"name\":\"tobi\"}');\n\n        text.originalFilename.should.equal('user.txt');\n        text.mimetype.should.equal('text/plain');\n        read(text.filepath).should.equal('Tobi');\n      });\n    });\n\n    describe('when a file does not exist', () => {\n      it('should fail the request with an error', (done) => {\n        const request_ = request.post(`${base}/echo`);\n\n        request_.attach('name', 'foo');\n        // request_.attach('name2', 'bar');\n        // request_.attach('name3', 'baz');\n\n        request_.end((error, res) => {\n          assert.ok(Boolean(error), 'Request should have failed.');\n          error.code.should.equal('ENOENT');\n          error.message.should.containEql('ENOENT');\n          if (IS_WINDOWS) {\n            error.path\n              .toLowerCase()\n              .should.equal(getFullPath('foo').toLowerCase());\n          } else {\n            error.path.should.equal(getFullPath('foo'));\n          }\n\n          done();\n        });\n      });\n\n      it('promise should fail', () => {\n        return request\n          .post(`${base}/echo`)\n          .field({ a: 1, b: 2 })\n          .attach('c', 'does-not-exist.txt')\n          .then(\n            (res) => assert.fail('It should not allow this'),\n            (err) => {\n              err.code.should.equal('ENOENT');\n              if (IS_WINDOWS) {\n                err.path\n                  .toLowerCase()\n                  .should.equal(\n                    getFullPath('does-not-exist.txt').toLowerCase()\n                  );\n              } else {\n                err.path.should.equal(getFullPath('does-not-exist.txt'));\n              }\n            }\n          );\n      });\n\n      it('should report ENOENT via the callback', (done) => {\n        request\n          .post(`${base}/echo`)\n          .attach('name', 'file-does-not-exist')\n          .end((error, res) => {\n            assert.ok(Boolean(error), 'Request should have failed');\n            error.code.should.equal('ENOENT');\n            done();\n          });\n      });\n\n      it('should report ENOENT via Promise', () => {\n        return request\n          .post(`${base}/echo`)\n          .attach('name', 'file-does-not-exist')\n          .then(\n            (res) => assert.fail('Request should have failed'),\n            (err) => err.code.should.equal('ENOENT')\n          );\n      });\n    });\n  });\n\n  describe('#attach(name, path, filename)', () => {\n    it('should use the custom filename', () =>\n      request\n        .post(`${base}/echo`)\n        .attach('document', 'test/node/fixtures/user.html', 'doc.html')\n        .then((res) => {\n          const html = res.files.document;\n          html.originalFilename.should.equal('doc.html');\n          html.mimetype.should.equal('text/html');\n          read(html.filepath).should.equal('<h1>name</h1>');\n        }));\n    it('should fire progress event', (done) => {\n      let loaded = 0;\n      let total = 0;\n      let uploadEventWasFired = false;\n      request\n        .post(`${base}/echo`)\n        .attach('document', 'test/node/fixtures/user.html')\n        .on('progress', (event) => {\n          total = event.total;\n          loaded = event.loaded;\n          if (event.direction === 'upload') {\n            uploadEventWasFired = true;\n          }\n        })\n        .end((error, res) => {\n          if (error) return done(error);\n          const html = res.files.document;\n          html.originalFilename.should.equal('user.html');\n          html.mimetype.should.equal('text/html');\n          read(html.filepath).should.equal('<h1>name</h1>');\n          total.should.equal(223);\n          loaded.should.equal(223);\n          uploadEventWasFired.should.equal(true);\n          done();\n        });\n    });\n    it('filesystem errors should be caught', (done) => {\n      request\n        .post(`${base}/echo`)\n        .attach('filedata', 'test/node/fixtures/non-existent-file.ext')\n        .end((error, res) => {\n          assert.ok(Boolean(error), 'Request should have failed.');\n          error.code.should.equal('ENOENT');\n          if (IS_WINDOWS) {\n            error.path\n              .toLowerCase()\n              .should.equal(\n                getFullPath(\n                  'test/node/fixtures/non-existent-file.ext'\n                ).toLowerCase()\n              );\n          } else {\n            error.path.should.equal(\n              getFullPath('test/node/fixtures/non-existent-file.ext')\n            );\n          }\n\n          done();\n        });\n    });\n  });\n\n  describe('#field(name, val)', () => {\n    it('should set a multipart field value', (done) => {\n      request\n        .post(`${base}/echo`)\n        .field('first-name', 'foo')\n        .field('last-name', 'bar')\n        .end((error, res) => {\n          if (error) done(error);\n          res.should.be.ok();\n          res.body['first-name'].should.equal('foo');\n          res.body['last-name'].should.equal('bar');\n          done();\n        });\n    });\n  });\n\n  describe('#field(object)', () => {\n    it('should set multiple multipart fields', (done) => {\n      request\n        .post(`${base}/echo`)\n        .field({ 'first-name': 'foo', 'last-name': 'bar' })\n        .end((error, res) => {\n          if (error) done(error);\n          res.should.be.ok();\n          res.body['first-name'].should.equal('foo');\n          res.body['last-name'].should.equal('bar');\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/network-error.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst net = require('net');\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nfunction getFreePort(fn) {\n  const server = net.createServer();\n  server.listen(0, () => {\n    const { port } = server.address();\n    server.close(() => {\n      fn(port);\n    });\n  });\n}\n\ndescribe('with network error', () => {\n  before(function (done) {\n    // connecting to a free port\n    // will trigger a connection refused\n    getFreePort((port) => {\n      this.port = port;\n      done();\n    });\n  });\n\n  it('should error', function (done) {\n    request.get(`http://localhost:${this.port}/`).end((error, res) => {\n      assert(error, 'expected an error');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/not-modified.js",
    "content": "'use strict';\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('request', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('not modified', () => {\n    let ts;\n    it('should start with 200', (done) => {\n      request.get(`${base}/if-mod`).end((error, res) => {\n        res.should.have.status(200);\n        res.text.should.match(/^\\d+$/);\n        ts = Number(res.text);\n        done();\n      });\n    });\n\n    it('should then be 304', (done) => {\n      request\n        .get(`${base}/if-mod`)\n        .set('If-Modified-Since', new Date(ts).toUTCString())\n        .end((error, res) => {\n          res.should.have.status(304);\n          // res.text.should.be.empty\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/parsers.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\nconst doesntWorkInHttp2 = !process.env.HTTP2_TEST;\n\ndescribe('req.parse(fn)', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should take precedence over default parsers', (done) => {\n    request\n      .get(`${base}/manny`)\n      .parse(request.parse['application/json'])\n      .end((error, res) => {\n        assert(res.ok);\n        assert.equal('{\"name\":\"manny\"}', res.text);\n        assert.equal('manny', res.body.name);\n        done();\n      });\n  });\n\n  it('should be the only parser', () =>\n    request\n      .get(`${base}/image`)\n      .buffer(false)\n      .parse((res, fn) => {\n        res.on('data', () => {});\n      })\n      .then((res) => {\n        assert(res.ok);\n        assert.strictEqual(res.text, undefined);\n        res.body.should.eql({});\n      }));\n\n  it('should emit error if parser throws', (done) => {\n    request\n      .get(`${base}/manny`)\n      .parse(() => {\n        throw new Error('I am broken');\n      })\n      .on('error', (error) => {\n        error.message.should.equal('I am broken');\n        done();\n      })\n      .end();\n  });\n\n  it('should emit error if parser returns an error', (done) => {\n    request\n      .get(`${base}/manny`)\n      .parse((res, fn) => {\n        fn(new Error('I am broken'));\n      })\n      .on('error', (error) => {\n        error.message.should.equal('I am broken');\n        done();\n      })\n      .end();\n  });\n\n  if (doesntWorkInHttp2)\n    it('should not emit error on chunked json', (done) => {\n      request.get(`${base}/chunked-json`).end((error) => {\n        assert.ifError(error);\n        done();\n      });\n    });\n\n  if (doesntWorkInHttp2)\n    it('should not emit error on aborted chunked json', (done) => {\n      const request_ = request.get(`${base}/chunked-json`);\n      request_.end((error) => {\n        assert.ifError(error);\n        done();\n      });\n\n      setTimeout(() => {\n        request_.abort();\n      }, 150);\n    });\n});\n"
  },
  {
    "path": "test/node/pipe-callback.js",
    "content": "const assert = require('node:assert');\nconst { Readable } = require('node:stream');\nconst getSetup = require('../support/setup');\nconst request = require('../support/client');\n\ndescribe('[node] pipe callback handling', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should work with pipe without callback', (done) => {\n    const body = Readable.from(JSON.stringify({ name: 'john' }));\n    const request_ = request\n      .post(`${base}/echo`)\n      .set('Content-Type', 'application/json')\n      .on('response', (res) => {\n        assert(res);\n        assert.equal(res.status, 200);\n        assert.equal(res.text, '{\"name\":\"john\"}');\n        done();\n      });\n\n    body.pipe(request_);\n  });\n\n  it('should work with pipe and callback', (done) => {\n    const body = Readable.from(JSON.stringify({ name: 'jane' }));\n    const request_ = request\n      .post(`${base}/echo`)\n      .set('Content-Type', 'application/json')\n      .on('response', (res) => {\n        assert(res);\n        assert.equal(res.status, 200);\n        assert.equal(res.text, '{\"name\":\"jane\"}');\n        done();\n      });\n\n    body.pipe(request_);\n  });\n});\n"
  },
  {
    "path": "test/node/pipe-redirect.js",
    "content": "'use strict';\nconst fs = require('fs');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('pipe on redirect', () => {\n  let setup;\n  let base;\n  const destinationPath = 'test/node/fixtures/pipe.txt';\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  after((done) => {\n    // Remove tmp file\n    fs.unlink(destinationPath, done);\n  });\n\n  it('should follow Location', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n    const redirects = [];\n    const request_ = request\n      .get(base)\n      .on('redirect', (res) => {\n        redirects.push(res.headers.location);\n      })\n      .connect({\n        inapplicable: 'should be ignored'\n      });\n    stream.on('finish', () => {\n      redirects.should.eql(['/movies', '/movies/all', '/movies/all/0']);\n      fs.readFileSync(destinationPath, 'utf8').should.eql('first movie page');\n      done();\n    });\n    request_.pipe(stream);\n  });\n});\n"
  },
  {
    "path": "test/node/pipe.js",
    "content": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\nconst fs = require('fs');\nconst bodyParser = require('body-parser');\nlet http = require('http');\nconst zlib = require('zlib');\nconst { pipeline } = require('stream');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\napp.use(bodyParser.json());\n\napp.get('/', (request_, res) => {\n  fs.createReadStream('test/node/fixtures/user.json').pipe(res);\n});\n\napp.get('/gzip', (request_, res) => {\n  res.writeHead(200, {\n    'Content-Encoding': 'gzip'\n  });\n  fs.createReadStream('test/node/fixtures/user.json').pipe(new zlib.createGzip()).pipe(res);\n});\n\napp.get('/redirect', (request_, res) => {\n  res.set('Location', '/').sendStatus(302);\n});\n\napp.get('/badRedirectNoLocation', (request_, res) => {\n  res.set('Location', '').sendStatus(302);\n});\n\napp.post('/', (request_, res) => {\n  if (process.env.HTTP2_TEST) {\n    // body-parser does not support http2 yet.\n    // This section can be remove after body-parser supporting http2.\n    res.set('content-type', 'application/json');\n    request_.pipe(res);\n  } else {\n    res.send(request_.body);\n  }\n});\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\ndescribe('request pipe', () => {\n  const destinationPath = 'test/node/fixtures/tmp.json';\n\n  after(function removeTmpfile(done) {\n    fs.unlink(destinationPath, done);\n  });\n\n  it('should act as a writable stream', (done) => {\n    const request_ = request.post(base);\n    const stream = fs.createReadStream('test/node/fixtures/user.json');\n\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      res.body.should.eql({ name: 'tobi' });\n      done();\n    });\n\n    stream.pipe(request_);\n  });\n\n  it('end() stops piping', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n    request.get(base).end((error, res) => {\n      try {\n        res.pipe(stream);\n        return done(new Error('Did not prevent nonsense pipe'));\n      } catch {\n        /* expected error */\n      }\n\n      done();\n    });\n  });\n\n  it('should act as a readable stream', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n\n    let responseCalled = false;\n    const request_ = request.get(base);\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      res.status.should.eql(200);\n      responseCalled = true;\n    });\n    stream.on('finish', () => {\n      JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n        name: 'tobi'\n      });\n      responseCalled.should.be.true();\n      done();\n    });\n    request_.pipe(stream);\n  });\n\n  it('should act as a readable stream with unzip', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n\n    let responseCalled = false;\n    const request_ = request.get(base + '/gzip');\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      res.status.should.eql(200);\n      responseCalled = true;\n    });\n    stream.on('finish', () => {\n      JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n        name: 'tobi'\n      });\n      responseCalled.should.be.true();\n      done();\n    });\n    request_.pipe(stream);\n  });\n\n  it('should act as a readable stream with unzip and node.stream.pipeline', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n\n    let responseCalled = false;\n    const request_ = request.get(base + '/gzip');\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      res.status.should.eql(200);\n      responseCalled = true;\n    });\n    // pipeline automatically ends streams by default.  Since unzipping introduces a transform stream that is\n    // not monitored by pipeline, we need to make sure request_ does not emit 'end' until the unzip step\n    // has finished writing data.  Otherwise, we'll either end up with truncated data or a 'write after end' error.\n    pipeline(request_, stream, function (err) {\n      (!!err).should.be.false();\n      responseCalled.should.be.true();\n\n      JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n        name: 'tobi'\n      });\n      done();\n    });\n  });\n\n  it('should follow redirects', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n\n    let responseCalled = false;\n    const request_ = request.get(base + '/redirect');\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      res.status.should.eql(200);\n      responseCalled = true;\n    });\n    stream.on('finish', () => {\n      JSON.parse(fs.readFileSync(destinationPath)).should.eql({\n        name: 'tobi'\n      });\n      responseCalled.should.be.true();\n      done();\n    });\n    request_.pipe(stream);\n  });\n\n  it('should not throw on bad redirects', (done) => {\n    const stream = fs.createWriteStream(destinationPath);\n\n    let responseCalled = false;\n    let errorCalled = false;\n    const request_ = request.get(base + '/badRedirectNoLocation');\n    request_.type('json');\n\n    request_.on('response', (res) => {\n      responseCalled = true;\n    });\n    request_.on('error', (error) => {\n      error.message.should.eql('No location header for redirect');\n      errorCalled = true;\n      stream.end();\n    });\n    stream.on('finish', () => {\n      responseCalled.should.be.false();\n      errorCalled.should.be.true();\n      done();\n    });\n    request_.pipe(stream);\n  });\n});\n"
  },
  {
    "path": "test/node/query.js",
    "content": "'use strict';\nlet http = require('http');\nconst assert = require('assert');\nconst fs = require('fs');\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\napp.get('/raw-query', (request_, res) => {\n  res.status(200).send(request_.url.slice(request_.url.indexOf('?') + 1));\n});\n\napp.get('/', (request_, res) => {\n  res.status(200).send(request_.query);\n});\n\napp.delete('/url', (request_, res) => {\n  res.status(200).send(request_.url);\n});\n\napp.delete('/', (request_, res) => {\n  res.status(200).send(request_.query);\n});\n\napp.put('/', (request_, res) => {\n  res.status(200).send(request_.query);\n});\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server = server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\ndescribe('req.query(String)', () => {\n  // This is no longer true as of qs v3.0.0 (https://github.com/ljharb/qs/commit/0c6f2a6318c94f6226d3cf7fe36094e9685042b6)\n  // it('should supply uri malformed error to the callback')\n\n  it('should support passing in a string', (done) => {\n    request\n      .del(base)\n      .query('name=t%F6bi')\n      .end((error, res) => {\n        res.body.should.eql({ name: 't%F6bi' });\n        done();\n      });\n  });\n\n  it('should work with url query-string and string for query', (done) => {\n    request\n      .del(`${base}/?name=tobi`)\n      .query('age=2%20')\n      .end((error, res) => {\n        res.body.should.eql({ name: 'tobi', age: '2 ' });\n        done();\n      });\n  });\n\n  it('should support compound elements in a string', (done) => {\n    request\n      .del(base)\n      .query('name=t%F6bi&age=2')\n      .end((error, res) => {\n        res.body.should.eql({ name: 't%F6bi', age: '2' });\n        done();\n      });\n  });\n\n  it('should work when called multiple times with a string', (done) => {\n    request\n      .del(base)\n      .query('name=t%F6bi')\n      .query('age=2%F6')\n      .end((error, res) => {\n        res.body.should.eql({ name: 't%F6bi', age: '2%F6' });\n        done();\n      });\n  });\n\n  it('should work with normal `query` object and query string', (done) => {\n    request\n      .del(base)\n      .query('name=t%F6bi')\n      .query({ age: '2' })\n      .end((error, res) => {\n        res.body.should.eql({ name: 't%F6bi', age: '2' });\n        done();\n      });\n  });\n\n  it('should not encode raw backticks, but leave encoded ones as is', () => {\n    return Promise.all([\n      request\n        .get(`${base}/raw-query`)\n        .query('name=`t%60bi`&age`=2')\n        .then((res) => {\n          res.text.should.eql('name=`t%60bi`&age`=2');\n        }),\n\n      request.get(base + '/raw-query?`age%60`=2%60`').then((res) => {\n        res.text.should.eql('`age%60`=2%60`');\n      }),\n\n      request\n        .get(`${base}/raw-query`)\n        .query('name=`t%60bi`')\n        .query('age`=2')\n        .then((res) => {\n          res.text.should.eql('name=`t%60bi`&age`=2');\n        })\n    ]);\n  });\n});\n\ndescribe('req.query(Object)', () => {\n  it('should construct the query-string', (done) => {\n    request\n      .del(base)\n      .query({ name: 'tobi' })\n      .query({ order: 'asc' })\n      .query({ limit: ['1', '2'] })\n      .end((error, res) => {\n        res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] });\n        done();\n      });\n  });\n\n  // See commit message for the reasoning here.\n  it('should encode raw backticks', (done) => {\n    request\n      .get(`${base}/raw-query`)\n      .query({ name: '`tobi`' })\n      .query({ 'orde%60r': null })\n      .query({ '`limit`': ['%602`'] })\n      .end((error, res) => {\n        res.text.should.eql('name=%60tobi%60&orde%2560r&%60limit%60=%25602%60');\n        done();\n      });\n  });\n\n  it('should not error on dates', (done) => {\n    const date = new Date(0);\n\n    request\n      .del(base)\n      .query({ at: date })\n      .end((error, res) => {\n        assert.equal(date.toISOString(), res.body.at);\n        done();\n      });\n  });\n\n  it('should work after setting header fields', (done) => {\n    request\n      .del(base)\n      .set('Foo', 'bar')\n      .set('Bar', 'baz')\n      .query({ name: 'tobi' })\n      .query({ order: 'asc' })\n      .query({ limit: ['1', '2'] })\n      .end((error, res) => {\n        res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] });\n        done();\n      });\n  });\n\n  it('should append to the original query-string', (done) => {\n    request\n      .del(`${base}/?name=tobi`)\n      .query({ order: 'asc' })\n      .end((error, res) => {\n        res.body.should.eql({ name: 'tobi', order: 'asc' });\n        done();\n      });\n  });\n\n  it('should retain the original query-string', (done) => {\n    request.del(`${base}/?name=tobi`).end((error, res) => {\n      res.body.should.eql({ name: 'tobi' });\n      done();\n    });\n  });\n\n  it('should keep only keys with null querystring values', (done) => {\n    request\n      .del(`${base}/url`)\n      .query({ nil: null })\n      .end((error, res) => {\n        res.text.should.equal('/url?nil');\n        done();\n      });\n  });\n\n  it('query-string should be sent on pipe', (done) => {\n    const request_ = request.put(`${base}/?name=tobi`);\n    const stream = fs.createReadStream('test/node/fixtures/user.json');\n\n    request_.on('response', (res) => {\n      res.body.should.eql({ name: 'tobi' });\n      done();\n    });\n    request_.on('error', (err) => {\n      done(err);\n    });\n\n    stream.on('error', (err) => {\n      done(err);\n    });\n\n    // wait until stream is valid before piping\n    stream.on('open', () => {\n      // wait until request_ is ready before piping\n      setTimeout(() => {\n        stream.pipe(request_);\n      }, 10);\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/redirects-other-host.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\nconst app2 = express();\nconst should = require('should');\nlet http = require('http');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server = server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\nlet base2 = 'http://localhost';\nlet server2;\nbefore(function listen(done) {\n  server2 = http.createServer(app2);\n  server2 = server2.listen(0, function listening() {\n    base2 += `:${server2.address().port}`;\n    done();\n  });\n});\n\napp.all('/test-301', (request_, res) => {\n  res.redirect(301, `${base2}/`);\n});\napp.all('/test-302', (request_, res) => {\n  res.redirect(302, `${base2}/`);\n});\napp.all('/test-303', (request_, res) => {\n  res.redirect(303, `${base2}/`);\n});\napp.all('/test-307', (request_, res) => {\n  res.redirect(307, `${base2}/`);\n});\napp.all('/test-308', (request_, res) => {\n  res.redirect(308, `${base2}/`);\n});\n\napp2.all('/', (request_, res) => {\n  res.send(request_.method);\n});\n\ndescribe('request.get', () => {\n  describe('on 301 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.get(`${base}/test-301`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 302 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.get(`${base}/test-302`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 303 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.get(`${base}/test-303`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 307 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.get(`${base}/test-307`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 308 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.get(`${base}/test-308`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n});\n\ndescribe('request.post', () => {\n  describe('on 301 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.post(`${base}/test-301`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 302 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.post(`${base}/test-302`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 303 redirect', () => {\n    it('should follow Location with a GET request', (done) => {\n      const request_ = request.post(`${base}/test-303`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('GET');\n        done();\n      });\n    });\n  });\n  describe('on 307 redirect', () => {\n    it('should follow Location with a POST request', (done) => {\n      const request_ = request.post(`${base}/test-307`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('POST');\n        done();\n      });\n    });\n  });\n  describe('on 308 redirect', () => {\n    it('should follow Location with a POST request', (done) => {\n      const request_ = request.post(`${base}/test-308`).redirects(1);\n      request_.end((error, res) => {\n        const headers = request_.req.getHeaders\n          ? request_.req.getHeaders()\n          : request_.req._headers;\n        headers.host.should.eql(`localhost:${server2.address().port}`);\n        res.status.should.eql(200);\n        res.text.should.eql('POST');\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/redirects.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst getSetup = require('../support/setup');\nconst request = require('../support/client');\n\ndescribe('request', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  describe('on redirect', () => {\n    it('should merge cookies if agent is used', (done) => {\n      request\n        .agent()\n        .get(`${base}/cookie-redirect`)\n        .set('Cookie', 'orig=1; replaced=not')\n        .end((error, res) => {\n          try {\n            assert.ifError(error);\n            assert(/orig=1/.test(res.text), 'orig=1/.test');\n            assert(/replaced=yes/.test(res.text), 'replaced=yes/.test');\n            assert(/from-redir=1/.test(res.text), 'from-redir=1');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should not merge cookies if agent is not used', (done) => {\n      request\n        .get(`${base}/cookie-redirect`)\n        .set('Cookie', 'orig=1; replaced=not')\n        .end((error, res) => {\n          try {\n            assert.ifError(error);\n            assert(/orig=1/.test(res.text), '/orig=1');\n            assert(/replaced=not/.test(res.text), '/replaced=not');\n            assert(!/replaced=yes/.test(res.text), '!/replaced=yes');\n            assert(!/from-redir/.test(res.text), '!/from-redir');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should have previously set cookie for subsquent requests when agent is used', (done) => {\n      const agent = request.agent();\n      agent.get(`${base}/set-cookie`).end((error) => {\n        assert.ifError(error);\n        agent\n          .get(`${base}/show-cookies`)\n          .set({ Cookie: 'orig=1' })\n          .end((error, res) => {\n            try {\n              assert.ifError(error);\n              assert(/orig=1/.test(res.text), 'orig=1/.test');\n              assert(/persist=123/.test(res.text), 'persist=123');\n              done();\n            } catch (err) {\n              done(err);\n            }\n          });\n      });\n    });\n\n    it('should overwrite previously set cookie during a redirect when agent is used', (done) => {\n      const agent = request.agent();\n      agent.get(`${base}/set-cookie`).end((error) => {\n        assert.ifError(error);\n        agent\n          .get(`${base}/cookie-redirect`)\n          .redirects(1)\n          .end((error, res) => {\n            try {\n              assert.ifError(error);\n              assert(/replaced=yes/.test(res.text), 'replaced=yes');\n              done();\n            } catch (err) {\n              done(err);\n            }\n          });\n      });\n    })\n\n    it('should follow Location', (done) => {\n      const redirects = [];\n\n      request\n        .get(base)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .end((error, res) => {\n          try {\n            const array = ['/movies', '/movies/all', '/movies/all/0'];\n            redirects.should.eql(array);\n            res.text.should.equal('first movie page');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should follow Location with IP override', () => {\n      const redirects = [];\n      const url = new URL(base);\n      return request\n        .get(`http://redir.example.com:${url.port || '80'}${url.pathname}`)\n        .connect({\n          '*': url.hostname\n        })\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .then((res) => {\n          const array = ['/movies', '/movies/all', '/movies/all/0'];\n          redirects.should.eql(array);\n          res.text.should.equal('first movie page');\n        });\n    });\n\n    it('should follow Location with IP:port override', () => {\n      const redirects = [];\n      const url = new URL(base);\n      return request\n        .get(`http://redir.example.com:9999${url.pathname}`)\n        .connect({\n          '*': { host: url.hostname, port: url.port || 80 }\n        })\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .then((res) => {\n          const array = ['/movies', '/movies/all', '/movies/all/0'];\n          redirects.should.eql(array);\n          res.text.should.equal('first movie page');\n        });\n    });\n\n    it('should not follow on HEAD by default', () => {\n      const redirects = [];\n\n      return request\n        .head(base)\n        .ok(() => true)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .then((res) => {\n          redirects.should.eql([]);\n          res.status.should.equal(302);\n        });\n    });\n\n    it('should follow on HEAD when redirects are set', (done) => {\n      const redirects = [];\n\n      request\n        .head(base)\n        .redirects(10)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .end((error, res) => {\n          try {\n            const array = [];\n            array.push('/movies', '/movies/all', '/movies/all/0');\n            redirects.should.eql(array);\n            assert(!res.text);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should remove Content-* fields', (done) => {\n      request\n        .post(`${base}/header`)\n        .type('txt')\n        .set('X-Foo', 'bar')\n        .set('X-Bar', 'baz')\n        .send('hey')\n        .end((error, res) => {\n          try {\n            assert(res.body);\n            res.body.should.have.property('x-foo', 'bar');\n            res.body.should.have.property('x-bar', 'baz');\n            res.body.should.not.have.property('content-type');\n            res.body.should.not.have.property('content-length');\n            res.body.should.not.have.property('transfer-encoding');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should retain cookies', (done) => {\n      request\n        .get(`${base}/header`)\n        .set('Cookie', 'foo=bar;')\n        .end((error, res) => {\n          try {\n            assert(res.body);\n            res.body.should.have.property('cookie', 'foo=bar;');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should not resend query parameters', (done) => {\n      const redirects = [];\n      const query = [];\n\n      request\n        .get(`${base}/?foo=bar`)\n        .on('redirect', (res) => {\n          query.push(res.headers.query);\n          redirects.push(res.headers.location);\n        })\n        .end((error, res) => {\n          try {\n            const array = [];\n            array.push('/movies', '/movies/all', '/movies/all/0');\n            redirects.should.eql(array);\n            res.text.should.equal('first movie page');\n\n            query.should.eql(['{\"foo\":\"bar\"}', '{}', '{}']);\n            res.headers.query.should.eql('{}');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should handle no location header', (done) => {\n      request.get(`${base}/bad-redirect`).end((error, res) => {\n        try {\n          error.message.should.equal('No location header for redirect');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n    });\n\n    describe('when relative', () => {\n      it('should redirect to a sibling path', (done) => {\n        const redirects = [];\n\n        request\n          .get(`${base}/relative`)\n          .on('redirect', (res) => {\n            redirects.push(res.headers.location);\n          })\n          .end((error, res) => {\n            try {\n              redirects.should.eql(['tobi']);\n              res.text.should.equal('tobi');\n              done();\n            } catch (err) {\n              done(err);\n            }\n          });\n      });\n\n      it('should redirect to a parent path', (done) => {\n        const redirects = [];\n\n        request\n          .get(`${base}/relative/sub`)\n          .on('redirect', (res) => {\n            redirects.push(res.headers.location);\n          })\n          .end((error, res) => {\n            try {\n              redirects.should.eql(['../tobi']);\n              res.text.should.equal('tobi');\n              done();\n            } catch (err) {\n              done(err);\n            }\n          });\n      });\n    });\n  });\n\n  describe('req.redirects(n)', () => {\n    it('should alter the default number of redirects to follow', (done) => {\n      const redirects = [];\n\n      request\n        .get(base)\n        .redirects(2)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .end((error, res) => {\n          try {\n            const array = [];\n            assert(res.redirect, 'res.redirect');\n            array.push('/movies', '/movies/all');\n            redirects.should.eql(array);\n            res.text.should.match(/Moved Temporarily|Found/);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n  });\n\n  describe('on POST', () => {\n    it('should redirect as GET', () => {\n      const redirects = [];\n\n      return request\n        .post(`${base}/movie`)\n        .send({ name: 'Tobi' })\n        .redirects(2)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .then((res) => {\n          redirects.should.eql(['/movies/all/0']);\n          res.text.should.equal('first movie page');\n        });\n    });\n\n    it('using multipart/form-data should redirect as GET', () => {\n      const redirects = [];\n\n      request\n        .post(`${base}/movie`)\n        .type('form')\n        .field('name', 'Tobi')\n        .redirects(2)\n        .on('redirect', (res) => {\n          redirects.push(res.headers.location);\n        })\n        .then((res) => {\n          redirects.should.eql(['/movies/all/0']);\n          res.text.should.equal('first movie page');\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/response-readable-stream.js",
    "content": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\nconst fs = require('fs');\nlet http = require('http');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\napp.get('/', (request_, res) => {\n  fs.createReadStream('test/node/fixtures/user.json').pipe(res);\n});\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server = server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\ndescribe('response', () => {\n  it('should act as a readable stream', (done) => {\n    const request_ = request.get(base).buffer(false);\n\n    request_.end((error, res) => {\n      if (error) return done(error);\n      let trackEndEvent = 0;\n      let trackCloseEvent = 0;\n\n      res.on('end', () => {\n        trackEndEvent++;\n        trackEndEvent.should.equal(1);\n        if (!process.env.HTTP2_TEST) {\n          trackCloseEvent.should.equal(0); // close should not have been called\n        }\n\n        done();\n      });\n\n      res.on('close', () => {\n        trackCloseEvent++;\n      });\n\n      setTimeout(() => {\n        (() => {\n          res.pause();\n        }).should.not.throw();\n        (() => {\n          res.resume();\n        }).should.not.throw();\n        (() => {\n          res.destroy();\n        }).should.not.throw();\n      }, 50);\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/serialize.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('req.serialize(fn)', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should take precedence over default parsers', (done) => {\n    request\n      .post(`${base}/echo`)\n      .send({ foo: 123 })\n      .serialize(() => '{\"bar\":456}')\n      .end((error, res) => {\n        assert.ifError(error);\n        assert.equal('{\"bar\":456}', res.text);\n        assert.equal(456, res.body.bar);\n        done();\n      });\n  });\n});\n"
  },
  {
    "path": "test/node/set-host.js",
    "content": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\nconst http = require('http');\nconst assert = require('assert');\n\ndescribe('request.get().set()', () => {\n  if (process.env.HTTP2_TEST) {\n    return; // request object doesn't look the same\n  }\n\n  let server;\n\n  after(function exitServer() {\n    if (typeof server.close === 'function') {\n      server.close();\n    } else {\n      server.destroy();\n    }\n  });\n\n  it('should set host header after get()', (done) => {\n    app.get('/', (request_, res) => {\n      assert.equal(request_.hostname, 'example.com');\n      res.end();\n    });\n\n    server = http.createServer(app);\n    server.listen(0, function listening() {\n      request\n        .get(`http://localhost:${server.address().port}`)\n        .set('host', 'example.com')\n        .then(() => {\n          return request\n            .get(`http://example.com:${server.address().port}`)\n            .connect({\n              'example.com': 'localhost',\n              '*': 'fail'\n            });\n        })\n        .then(() => done(), done);\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/toError.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = express();\nlet http = require('http');\n\nif (process.env.HTTP2_TEST) {\n  http = require('http2');\n}\n\napp.get('/', (request_, res) => {\n  res.status(400).send('invalid json');\n});\n\nlet base = 'http://localhost';\nlet server;\nbefore(function listen(done) {\n  server = http.createServer(app);\n  server = server.listen(0, function listening() {\n    base += `:${server.address().port}`;\n    done();\n  });\n});\n\ndescribe('res.toError()', () => {\n  it('should return an Error', (done) => {\n    request.get(base).end((err, res) => {\n      const error = res.toError();\n      assert.equal(error.status, 400);\n      assert.equal(error.method, 'GET');\n      assert.equal(error.path, '/');\n      assert.equal(error.message, 'cannot GET / (400)');\n      assert.equal(error.text, 'invalid json');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "test/node/unix-sockets.js",
    "content": "'use strict';\nconst assert = require('assert');\n\nlet http = require('http');\nlet https = require('https');\nconst os = require('os');\nconst fs = require('fs');\nconst express = require('../support/express');\nconst request = require('../support/client');\n\nconst app = express();\n\nconst key = fs.readFileSync(`${__dirname}/fixtures/key.pem`);\nconst cert = fs.readFileSync(`${__dirname}/fixtures/cert.pem`);\nconst cacert = fs.readFileSync(`${__dirname}/fixtures/ca.cert.pem`);\nconst httpSockPath = [os.tmpdir(), 'superagent-http.sock'].join('/');\nconst httpsSockPath = [os.tmpdir(), 'superagent-https.sock'].join('/');\nlet httpServer;\nlet httpsServer;\n\nif (process.env.HTTP2_TEST) {\n  http = https = require('http2');\n}\n\napp.get('/', (request_, res) => {\n  res.send('root ok!');\n});\n\napp.get('/request/path', (request_, res) => {\n  res.send('request path ok!');\n});\n\ndescribe('[unix-sockets] http', () => {\n  if (process.platform === 'win32') {\n    return;\n  }\n\n  before((done) => {\n    if (fs.existsSync(httpSockPath) === true) {\n      // try unlink if sock file exists\n      fs.unlinkSync(httpSockPath);\n    }\n\n    httpServer = http.createServer(app);\n    httpServer.listen(httpSockPath, done);\n  });\n\n  const base = `http+unix://${httpSockPath.replace(/\\//g, '%2F')}`;\n\n  describe('request', () => {\n    it('path: / (root)', (done) => {\n      request.get(`${base}/`).end((error, res) => {\n        assert(res.ok);\n        assert.strictEqual('root ok!', res.text);\n        done();\n      });\n    });\n\n    it('path: /request/path', (done) => {\n      request.get(`${base}/request/path`).end((error, res) => {\n        assert(res.ok);\n        assert.strictEqual('request path ok!', res.text);\n        done();\n      });\n    });\n  });\n\n  after(() => {\n    if (typeof httpServer.close === 'function') {\n      httpServer.close();\n    } else httpServer.destroy();\n  });\n});\n\ndescribe('[unix-sockets] https', () => {\n  if (process.platform === 'win32') {\n    return;\n  }\n\n  before((done) => {\n    if (fs.existsSync(httpsSockPath) === true) {\n      // try unlink if sock file exists\n      fs.unlinkSync(httpsSockPath);\n    }\n\n    httpsServer = process.env.HTTP2_TEST\n      ? https.createSecureServer({ key, cert }, app)\n      : https.createServer({ key, cert }, app);\n\n    httpsServer.listen(httpsSockPath, done);\n  });\n\n  const base = `https+unix://${httpsSockPath.replace(/\\//g, '%2F')}`;\n\n  describe('request', () => {\n    it('path: / (root)', (done) => {\n      request\n        .get(`${base}/`)\n        .ca(cacert)\n        .end((error, res) => {\n          assert.ifError(error);\n          assert(res.ok);\n          assert.strictEqual('root ok!', res.text);\n          done();\n        });\n    });\n\n    it('path: /request/path', (done) => {\n      request\n        .get(`${base}/request/path`)\n        .ca(cacert)\n        .end((error, res) => {\n          assert.ifError(error);\n          assert(res.ok);\n          assert.strictEqual('request path ok!', res.text);\n          done();\n        });\n    });\n  });\n\n  after((done) => {\n    httpsServer.close(done);\n  });\n});\n"
  },
  {
    "path": "test/node/user-agent.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('req.get()', () => {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  it('should not set a default user-agent', () =>\n    request.get(`${base}/ua`).then((res) => {\n      assert(res.headers);\n      assert(!res.headers['user-agent']);\n    }));\n});\n"
  },
  {
    "path": "test/node/utils.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst utils =\n  process.env.OLD_NODE_TEST === '1'\n    ? // eslint-disable-next-line node/no-missing-require\n      require('../../../utils')\n    : require('../../lib/utils');\n\ndescribe('utils.type(str)', () => {\n  it('should return the mime type', () => {\n    utils\n      .type('application/json; charset=utf-8')\n      .should.equal('application/json');\n\n    utils.type('application/json').should.equal('application/json');\n  });\n});\n\ndescribe('utils.params(str)', () => {\n  it('should return the field parameters', () => {\n    const object = utils.params('application/json; charset=utf-8; foo  = bar');\n    object.charset.should.equal('utf-8');\n    object.foo.should.equal('bar');\n\n    utils.params('application/json').should.eql({});\n  });\n});\n\ndescribe('utils.parseLinks(str)', () => {\n  it('should parse links', () => {\n    const string_ =\n      '<https://api.github.com/repos/visionmedia/mocha/issues?page=2>; rel=\"next\", <https://api.github.com/repos/visionmedia/mocha/issues?page=5>; rel=\"last\"';\n    const returnValue = utils.parseLinks(string_);\n    returnValue.next.should.equal(\n      'https://api.github.com/repos/visionmedia/mocha/issues?page=2'\n    );\n    returnValue.last.should.equal(\n      'https://api.github.com/repos/visionmedia/mocha/issues?page=5'\n    );\n  });\n});\n\ndescribe('utils.isGzipOrDeflateEncoding(res)', () => {\n  it('should return true when content encoding is gzip', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': 'gzip',\n      },\n    }).should.equal(true);\n  });\n  it('should return true when content encoding is deflate', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': 'deflate',\n      },\n    }).should.equal(true);\n  });\n  it('should return false when content encoding is bla', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': 'bla',\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding has a lot of spaces followed with gzip', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': \" \" * 10**6 + \" gzip\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding repeates it self', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': \"gzip deflate gzip deflate gzip deflate gzip deflate gzip deflate gzip deflate gzip deflate gzip deflate\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding repeates it self wuth a lot of spaces', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': \" gzip   deflate   gzip   deflate   gzip   deflate   gzip   deflate   gzip   deflate   gzip   deflate\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding - nested patterns', () => {\n    utils.isGzipOrDeflateEncoding({\n      headers: {\n        'content-encoding': \" \" * 10**5 + (\"gzip deflate \" * 1000)\n      },\n    }).should.equal(false);\n  });\n\n  \n});\n\ndescribe('utils.isBrotliEncoding(res)', () => {\n  it('should return true when content encoding is br', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': 'br',\n      },\n    }).should.equal(true);\n  });\n  it('should return false when content encoding is bla', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': 'bla',\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding has a lot of spaces followed with br', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': \" \" * 10**6 + \" br\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding repeates it self', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': \" br br br br br  br br br br br  br br br br br br br br br br  br br br br br  br br br br br\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding repeates it self wuth a lot of spaces', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': \"br     br     br     br     br     br     br     br     br     br     br     br     br     br\",\n      },\n    }).should.equal(false);\n  });\n  \n  it('should return true when content encoding - nested patterns', () => {\n    utils.isBrotliEncoding({\n      headers: {\n        'content-encoding': \" \" * 10**5 + (\"br \" * 1000)\n      },\n    }).should.equal(false);\n  });\n  \n});\n"
  },
  {
    "path": "test/redirects.js",
    "content": "const assert = require('assert');\n\nconst getSetup = require('./support/setup');\nconst request = require('./support/client');\n\ndescribe('request', function () {\n  let setup;\n  let base;\n  let isMSIE;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n    isMSIE = !setup.NODE && /Trident\\//.test(navigator.userAgent);\n  });\n\n  this.timeout(20_000);\n  describe('on redirect', () => {\n    it('should retain header fields', (done) => {\n      request\n        .get(`${base}/header`)\n        .set('X-Foo', 'bar')\n        .end((error, res) => {\n          try {\n            assert(res.body);\n            res.body.should.have.property('x-foo', 'bar');\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should preserve timeout across redirects', (done) => {\n      request\n        .get(`${base}/movies/random`)\n        .timeout(250)\n        .end((error, res) => {\n          try {\n            assert(error instanceof Error, 'expected an error');\n            error.should.have.property('timeout', 250);\n            done();\n          } catch (err) {\n            done(err);\n          }\n        });\n    });\n\n    it('should successfully redirect after retry on error', (done) => {\n      const id = Math.random() * 1_000_000 * Date.now();\n      request\n        .get(`${base}/error/redirect/${id}`)\n        .retry(2)\n        .end((error, res) => {\n          assert(res.ok, 'response should be ok');\n          assert(res.text, 'first movie page');\n          done();\n        });\n    });\n\n    it('should preserve retries across redirects', (done) => {\n      const id = Math.random() * 1_000_000 * Date.now();\n      request\n        .get(`${base}/error/redirect-error${id}`)\n        .retry(2)\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(2, error.retries, 'expected an error with .retries');\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        });\n    });\n  });\n\n  describe('on 303', () => {\n    it('should redirect with same method', (done) => {\n      request\n        .put(`${base}/redirect-303`)\n        .send({ msg: 'hello' })\n        .redirects(1)\n        .on('redirect', (res) => {\n          res.headers.location.should.equal('/reply-method');\n        })\n        .end((error, res) => {\n          if (error) {\n            done(error);\n            return;\n          }\n\n          res.text.should.equal('method=get');\n          done();\n        });\n    });\n  });\n\n  describe('on 307', () => {\n    it('should redirect with same method', (done) => {\n      if (isMSIE) return done(); // IE9 broken\n\n      request\n        .put(`${base}/redirect-307`)\n        .send({ msg: 'hello' })\n        .redirects(1)\n        .on('redirect', (res) => {\n          res.headers.location.should.equal('/reply-method');\n        })\n        .end((error, res) => {\n          if (error) {\n            done(error);\n            return;\n          }\n\n          res.text.should.equal('method=put');\n          done();\n        });\n    });\n  });\n\n  describe('on 308', () => {\n    it('should redirect with same method', (done) => {\n      if (isMSIE) return done(); // IE9 broken\n\n      request\n        .put(`${base}/redirect-308`)\n        .send({ msg: 'hello' })\n        .redirects(1)\n        .on('redirect', (res) => {\n          res.headers.location.should.equal('/reply-method');\n        })\n        .end((error, res) => {\n          if (error) {\n            done(error);\n            return;\n          }\n\n          res.text.should.equal('method=put');\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/request.js",
    "content": "const fs = require('fs');\n\nconst assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\nconst binData = fs.readFileSync(`${__dirname}/node/fixtures/test.aac`);\n\ndescribe('request', function () {\n  let setup;\n  let uri;\n\n  before(async () => {\n    setup = await getSetup();\n    uri = setup.uri;\n  });\n\n  this.timeout(20_000);\n\n  it('Request inheritance', () => {\n    assert(request.get(`${uri}/`) instanceof request.Request);\n  });\n\n  it('request() simple GET without callback', (next) => {\n    request('GET', 'test/test.request.js').end();\n    next();\n  });\n\n  it('request() simple GET', (next) => {\n    request('GET', `${uri}/ok`).end((error, res) => {\n      try {\n        assert(res instanceof request.Response, 'respond with Response');\n        assert(res.ok, 'response should be ok');\n        assert(res.text, 'res.text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() simple HEAD', (next) => {\n    request.head(`${uri}/ok`).end((error, res) => {\n      try {\n        assert(res instanceof request.Response, 'respond with Response');\n        assert(res.ok, 'response should be ok');\n        assert(!res.text, 'res.text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 5xx', (next) => {\n    request('GET', `${uri}/error`).end((error, res) => {\n      try {\n        assert(error);\n        assert.equal(error.message, 'Internal Server Error');\n        assert(!res.ok, 'response should not be ok');\n        assert(res.error, 'response should be an error');\n        assert(!res.clientError, 'response should not be a client error');\n        assert(res.serverError, 'response should be a server error');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 4xx', (next) => {\n    request('GET', `${uri}/notfound`).end((error, res) => {\n      try {\n        assert(error);\n        assert.equal(error.message, 'Not Found');\n        assert(!res.ok, 'response should not be ok');\n        assert(res.error, 'response should be an error');\n        assert(res.clientError, 'response should be a client error');\n        assert(!res.serverError, 'response should not be a server error');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 404 Not Found', (next) => {\n    request('GET', `${uri}/notfound`).end((error, res) => {\n      try {\n        assert(error);\n        assert(res.notFound, 'response should be .notFound');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 400 Bad Request', (next) => {\n    request('GET', `${uri}/bad-request`).end((error, res) => {\n      try {\n        assert(error);\n        assert(res.badRequest, 'response should be .badRequest');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 401 Bad Request', (next) => {\n    request('GET', `${uri}/unauthorized`).end((error, res) => {\n      try {\n        assert(error);\n        assert(res.unauthorized, 'response should be .unauthorized');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 406 Not Acceptable', (next) => {\n    request('GET', `${uri}/not-acceptable`).end((error, res) => {\n      try {\n        assert(error);\n        assert(res.notAcceptable, 'response should be .notAcceptable');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() GET 204 No Content', (next) => {\n    request('GET', `${uri}/no-content`).end((error, res) => {\n      try {\n        assert.ifError(error);\n        assert(res.noContent, 'response should be .noContent');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() DELETE 204 No Content', (next) => {\n    request('DELETE', `${uri}/no-content`).end((error, res) => {\n      try {\n        assert.ifError(error);\n        assert(res.noContent, 'response should be .noContent');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() header parsing', (next) => {\n    request('GET', `${uri}/notfound`).end((error, res) => {\n      try {\n        assert(error);\n        assert.equal('text/html; charset=utf-8', res.header['content-type']);\n        assert.equal('Express', res.header['x-powered-by']);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request() .status', (next) => {\n    request('GET', `${uri}/notfound`).end((error, res) => {\n      try {\n        assert(error);\n        assert.equal(404, res.status, 'response .status');\n        assert.equal(4, res.statusType, 'response .statusType');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('get()', (next) => {\n    request.get(`${uri}/notfound`).end((error, res) => {\n      try {\n        assert(error);\n        assert.equal(404, res.status, 'response .status');\n        assert.equal(4, res.statusType, 'response .statusType');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('put()', (next) => {\n    request.put(`${uri}/user/12`).end((error, res) => {\n      try {\n        assert.equal('updated', res.text, 'response text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('put().send()', (next) => {\n    request\n      .put(`${uri}/user/13/body`)\n      .send({ user: 'new' })\n      .end((error, res) => {\n        try {\n          assert.equal('received new', res.text, 'response text');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('post()', (next) => {\n    request.post(`${uri}/user`).end((error, res) => {\n      try {\n        assert.equal('created', res.text, 'response text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('del()', (next) => {\n    request.del(`${uri}/user/12`).end((error, res) => {\n      try {\n        assert.equal('deleted', res.text, 'response text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('delete()', (next) => {\n    request.delete(`${uri}/user/12`).end((error, res) => {\n      try {\n        assert.equal('deleted', res.text, 'response text');\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('post() data', (next) => {\n    request\n      .post(`${uri}/todo/item`)\n      .type('application/octet-stream')\n      .send('tobi')\n      .end((error, res) => {\n        try {\n          assert.equal('added \"tobi\"', res.text, 'response text');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .type()', (next) => {\n    request\n      .post(`${uri}/user/12/pet`)\n      .type('urlencoded')\n      .send('pet=tobi')\n      .end((error, res) => {\n        try {\n          assert.equal('added pet \"tobi\"', res.text, 'response text');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .type() with alias', (next) => {\n    request\n      .post(`${uri}/user/12/pet`)\n      .type('application/x-www-form-urlencoded')\n      .send('pet=tobi')\n      .end((error, res) => {\n        try {\n          assert.equal('added pet \"tobi\"', res.text, 'response text');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .get() with no data or callback', (next) => {\n    request.get(`${uri}/echo-header/content-type`);\n    next();\n  });\n\n  it('request .send() with no data only', (next) => {\n    request.post(`${uri}/user/5/pet`).type('urlencoded').send('pet=tobi');\n    next();\n  });\n\n  it('request .send() with callback only', (next) => {\n    request\n      .get(`${uri}/echo-header/accept`)\n      .set('Accept', 'foo/bar')\n      .end((error, res) => {\n        try {\n          assert.equal('foo/bar', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .accept() with json', (next) => {\n    request\n      .get(`${uri}/echo-header/accept`)\n      .accept('json')\n      .end((error, res) => {\n        try {\n          assert.equal('application/json', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .accept() with application/json', (next) => {\n    request\n      .get(`${uri}/echo-header/accept`)\n      .accept('application/json')\n      .end((error, res) => {\n        try {\n          assert.equal('application/json', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .accept() with xml', (next) => {\n    request\n      .get(`${uri}/echo-header/accept`)\n      .accept('xml')\n      .end((error, res) => {\n        try {\n          // We can't depend on mime module to be consistent with this\n          assert(res.text == 'application/xml' || res.text == 'text/xml');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .accept() with application/xml', (next) => {\n    request\n      .get(`${uri}/echo-header/accept`)\n      .accept('application/xml')\n      .end((error, res) => {\n        try {\n          assert.equal('application/xml', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  // FIXME: ie6 will POST rather than GET here due to data(),\n  //        but I'm not 100% sure why.  Newer IEs are OK.\n  it('request .end()', (next) => {\n    request\n      .put(`${uri}/echo-header/content-type`)\n      .set('Content-Type', 'text/plain')\n      .send('wahoo')\n      .end((error, res) => {\n        try {\n          assert.equal('text/plain', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .send()', (next) => {\n    request\n      .put(`${uri}/echo-header/content-type`)\n      .set('Content-Type', 'text/plain')\n      .send('wahoo')\n      .end((error, res) => {\n        try {\n          assert.equal('text/plain', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .set()', (next) => {\n    request\n      .put(`${uri}/echo-header/content-type`)\n      .set('Content-Type', 'text/plain')\n      .send('wahoo')\n      .end((error, res) => {\n        try {\n          assert.equal('text/plain', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('request .set(object)', (next) => {\n    request\n      .put(`${uri}/echo-header/content-type`)\n      .set({ 'Content-Type': 'text/plain' })\n      .send('wahoo')\n      .end((error, res) => {\n        try {\n          assert.equal('text/plain', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST urlencoded', (next) => {\n    request\n      .post(`${uri}/pet`)\n      .type('urlencoded')\n      .send({ name: 'Manny', species: 'cat' })\n      .end((error, res) => {\n        try {\n          assert.equal('added Manny the cat', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST json', (next) => {\n    request\n      .post(`${uri}/pet`)\n      .type('json')\n      .send({ name: 'Manny', species: 'cat' })\n      .end((error, res) => {\n        try {\n          assert.equal('added Manny the cat', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST json array', (next) => {\n    request\n      .post(`${uri}/echo`)\n      .send([1, 2, 3])\n      .end((error, res) => {\n        try {\n          assert.equal(\n            'application/json',\n            res.header['content-type'].split(';')[0]\n          );\n          assert.equal('[1,2,3]', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST json default', (next) => {\n    request\n      .post(`${uri}/pet`)\n      .send({ name: 'Manny', species: 'cat' })\n      .end((error, res) => {\n        try {\n          assert.equal('added Manny the cat', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST json contentType charset', (next) => {\n    request\n      .post(`${uri}/echo`)\n      .set('Content-Type', 'application/json; charset=UTF-8')\n      .send({ data: ['data1', 'data2'] })\n      .end((error, res) => {\n        try {\n          assert.equal('{\"data\":[\"data1\",\"data2\"]}', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST json contentType vendor', (next) => {\n    request\n      .post(`${uri}/echo`)\n      .set('Content-Type', 'application/vnd.example+json')\n      .send({ data: ['data1', 'data2'] })\n      .end((error, res) => {\n        try {\n          assert.equal('{\"data\":[\"data1\",\"data2\"]}', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST multiple .send() calls', (next) => {\n    request\n      .post(`${uri}/pet`)\n      .send({ name: 'Manny' })\n      .send({ species: 'cat' })\n      .end((error, res) => {\n        try {\n          assert.equal('added Manny the cat', res.text);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST multiple .send() strings', (next) => {\n    request\n      .post(`${uri}/echo`)\n      .send('user[name]=tj')\n      .send('user[email]=tj@vision-media.ca')\n      .end((error, res) => {\n        try {\n          assert.equal(\n            'application/x-www-form-urlencoded',\n            res.header['content-type'].split(';')[0]\n          );\n          assert.equal(\n            res.text,\n            'user[name]=tj&user[email]=tj@vision-media.ca'\n          );\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('POST with no data', (next) => {\n    request\n      .post(`${uri}/empty-body`)\n      .send()\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert(res.noContent, 'response should be .noContent');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET .type', (next) => {\n    request.get(`${uri}/pets`).end((error, res) => {\n      try {\n        assert.equal('application/json', res.type);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('GET Content-Type params', (next) => {\n    request.get(`${uri}/text`).end((error, res) => {\n      try {\n        assert.equal('utf-8', res.charset);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('GET json', (next) => {\n    request.get(`${uri}/pets`).end((error, res) => {\n      try {\n        assert.deepEqual(res.body, ['tobi', 'loki', 'jane']);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('GET json-seq', (next) => {\n    request\n      .get(`${uri}/json-seq`)\n      .buffer()\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert.deepEqual(res.text, '\\u001E{\"id\":1}\\n\\u001E{\"id\":2}\\n');\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET binary data', (next) => {\n    request\n      .get(`${uri}/binary-data`)\n      .buffer()\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert.deepEqual(res.body, binData);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET x-www-form-urlencoded', (next) => {\n    request.get(`${uri}/foo`).end((error, res) => {\n      try {\n        assert.deepEqual(res.body, { foo: 'bar' });\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('GET shorthand', (next) => {\n    request.get(`${uri}/foo`, (error, res) => {\n      try {\n        assert.equal('foo=bar', res.text);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('POST shorthand', (next) => {\n    request.post(`${uri}/user/0/pet`, { pet: 'tobi' }, (error, res) => {\n      try {\n        assert.equal('added pet \"tobi\"', res.text);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('POST shorthand without callback', (next) => {\n    request.post(`${uri}/user/0/pet`, { pet: 'tobi' }).end((error, res) => {\n      try {\n        assert.equal('added pet \"tobi\"', res.text);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('GET querystring object with array', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query({ val: ['a', 'b', 'c'] })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, { val: ['a', 'b', 'c'] });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring object with array and primitives', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query({ array: ['a', 'b', 'c'], string: 'foo', number: 10 })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, {\n            array: ['a', 'b', 'c'],\n            string: 'foo',\n            number: 10\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring object with two arrays', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query({ array1: ['a', 'b', 'c'], array2: [1, 2, 3] })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, {\n            array1: ['a', 'b', 'c'],\n            array2: [1, 2, 3]\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring object', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query({ search: 'Manny' })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, { search: 'Manny' });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring append original', (next) => {\n    request\n      .get(`${uri}/querystring?search=Manny`)\n      .query({ range: '1..5' })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, { search: 'Manny', range: '1..5' });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring multiple objects', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query({ search: 'Manny' })\n      .query({ range: '1..5' })\n      .query({ order: 'desc' })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, {\n            search: 'Manny',\n            range: '1..5',\n            order: 'desc'\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring with strings', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query('search=Manny')\n      .query('range=1..5')\n      .query('order=desc')\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, {\n            search: 'Manny',\n            range: '1..5',\n            order: 'desc'\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET querystring with strings and objects', (next) => {\n    request\n      .get(`${uri}/querystring`)\n      .query('search=Manny')\n      .query({ order: 'desc', range: '1..5' })\n      .end((error, res) => {\n        try {\n          assert.deepEqual(res.body, {\n            search: 'Manny',\n            range: '1..5',\n            order: 'desc'\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      });\n  });\n\n  it('GET shorthand payload goes to querystring', (next) => {\n    request.get(\n      `${uri}/querystring`,\n      { foo: 'FOO', bar: 'BAR' },\n      (error, res) => {\n        try {\n          assert.deepEqual(res.body, { foo: 'FOO', bar: 'BAR' });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      }\n    );\n  });\n\n  it('HEAD shorthand payload goes to querystring', (next) => {\n    request.head(\n      `${uri}/querystring-in-header`,\n      { foo: 'FOO', bar: 'BAR' },\n      (error, res) => {\n        try {\n          assert.deepEqual(JSON.parse(res.headers.query), {\n            foo: 'FOO',\n            bar: 'BAR'\n          });\n          next();\n        } catch (err) {\n          next(err);\n        }\n      }\n    );\n  });\n\n  it('request(method, url)', (next) => {\n    request('GET', `${uri}/foo`).end((error, res) => {\n      try {\n        assert.equal('bar', res.body.foo);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request(url)', (next) => {\n    request(`${uri}/foo`).end((error, res) => {\n      try {\n        assert.equal('bar', res.body.foo);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request(url, fn)', (next) => {\n    request(`${uri}/foo`, (error, res) => {\n      try {\n        assert.equal('bar', res.body.foo);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('req.timeout(ms)', (next) => {\n    const request_ = request.get(`${uri}/delay/3000`).timeout(1000);\n    request_.end((error, res) => {\n      try {\n        assert(error, 'error missing');\n        assert.equal(1000, error.timeout, 'err.timeout missing');\n        assert.equal(\n          'Timeout of 1000ms exceeded',\n          error.message,\n          'err.message incorrect'\n        );\n        assert.equal(null, res);\n        assert(request_.timedout, true);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('req.timeout(ms) with redirect', (next) => {\n    const request_ = request.get(`${uri}/delay/const`).timeout(1000);\n    request_.end((error, res) => {\n      try {\n        assert(error, 'error missing');\n        assert.equal(1000, error.timeout, 'err.timeout missing');\n        assert.equal(\n          'Timeout of 1000ms exceeded',\n          error.message,\n          'err.message incorrect'\n        );\n        assert.equal(null, res);\n        assert(request_.timedout, true);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('request event', (next) => {\n    request\n      .get(`${uri}/foo`)\n      .on('request', (request_) => {\n        try {\n          assert.equal(`${uri}/foo`, request_.url);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      })\n      .end();\n  });\n\n  it('response event', (next) => {\n    request\n      .get(`${uri}/foo`)\n      .on('response', (res) => {\n        try {\n          assert.equal('bar', res.body.foo);\n          next();\n        } catch (err) {\n          next(err);\n        }\n      })\n      .end();\n  });\n\n  it('response should set statusCode', (next) => {\n    request.get(`${uri}/ok`, (error, res) => {\n      try {\n        assert.strictEqual(res.statusCode, 200);\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n\n  it('req.toJSON()', (next) => {\n    request.get(`${uri}/ok`).end((error, res) => {\n      try {\n        const index = (res.request || res.req).toJSON();\n        for (const property of ['url', 'method', 'data', 'headers']) {\n          assert(index.hasOwnProperty(property));\n        }\n\n        next();\n      } catch (err) {\n        next(err);\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "test/retry.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\nfunction uniqid() {\n  return Math.random() * 10_000_000;\n}\n\ndescribe('.retry(count)', function () {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  this.timeout(15_000);\n\n  it('should not retry if passed \"0\"', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry(0)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(\n            undefined,\n            error.retries,\n            'expected an error without .retries'\n          );\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should not retry if passed an invalid number', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry(-2)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(\n            undefined,\n            error.retries,\n            'expected an error without .retries'\n          );\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should not retry if passed undefined', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry(undefined)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(\n            undefined,\n            error.retries,\n            'expected an error without .retries'\n          );\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should handle server error after repeat attempt', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry(2)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(2, error.retries, 'expected an error with .retries');\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should retry if passed nothing', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry()\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(1, error.retries, 'expected an error with .retries');\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should retry if passed \"true\"', (done) => {\n    request\n      .get(`${base}/error`)\n      .retry(true)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(1, error.retries, 'expected an error with .retries');\n          assert.equal(500, error.status, 'expected an error status of 500');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should handle successful request after repeat attempt from server error', (done) => {\n    request\n      .get(`${base}/error/ok/${uniqid()}`)\n      .query({ qs: 'present' })\n      .retry(2)\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert(res.ok, 'response should be ok');\n          assert(res.text, 'res.text');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should handle server timeout error after repeat attempt', (done) => {\n    request\n      .get(`${base}/delay/400`)\n      .timeout(200)\n      .retry(2)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(2, error.retries, 'expected an error with .retries');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should handle successful request after repeat attempt from server timeout', (done) => {\n    const url = `/delay/1200/ok/${uniqid()}?built=in`;\n    request\n      .get(base + url)\n      .query('string=ified')\n      .query({ json: 'ed' })\n      .timeout(600)\n      .retry(2)\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert(res.ok, 'response should be ok');\n          assert.equal(res.text, `ok = ${url}&string=ified&json=ed`);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should handle successful request after repeat attempt from server timeout when using .then(fulfill, reject)', (done) => {\n    const url = `/delay/1200/ok/${uniqid()}?built=in`;\n    request\n      .get(base + url)\n      .query('string=ified')\n      .query({ json: 'ed' })\n      .timeout(600)\n      .retry(1)\n      .then((res, error) => {\n        try {\n          assert.ifError(error);\n          assert(res.ok, 'response should be ok');\n          assert.equal(res.text, `ok = ${url}&string=ified&json=ed`);\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should correctly abort a retry attempt', (done) => {\n    let aborted = false;\n    const request_ = request.get(`${base}/delay/400`).timeout(200).retry(2);\n    request_.end((error, res) => {\n      try {\n        assert(false, 'should not complete the request');\n      } catch (err) {\n        done(err);\n      }\n    });\n\n    request_.on('abort', () => {\n      aborted = true;\n    });\n\n    setTimeout(() => {\n      request_.abort();\n      setTimeout(() => {\n        try {\n          assert(aborted, 'should be aborted');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      }, 150);\n    }, 150);\n  });\n\n  it('should correctly retain header fields', (done) => {\n    request\n      .get(`${base}/error/ok/${uniqid()}`)\n      .query({ qs: 'present' })\n      .retry(2)\n      .set('X-Foo', 'bar')\n      .end((error, res) => {\n        try {\n          assert.ifError(error);\n          assert(res.body);\n          res.body.should.have.property('x-foo', 'bar');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should not retry on 4xx responses', (done) => {\n    request\n      .get(`${base}/bad-request`)\n      .retry(2)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(0, error.retries, 'expected an error with 0 .retries');\n          assert.equal(400, error.status, 'expected an error status of 400');\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n\n  it('should execute callback on retry if passed', (done) => {\n    let callbackCallCount = 0;\n    function retryCallback(request) {\n      callbackCallCount++;\n    }\n\n    request\n      .get(`${base}/error`)\n      .retry(2, retryCallback)\n      .end((error, res) => {\n        try {\n          assert(error, 'expected an error');\n          assert.equal(2, error.retries, 'expected an error with .retries');\n          assert.equal(500, error.status, 'expected an error status of 500');\n          assert.equal(\n            2,\n            callbackCallCount,\n            'expected the callback to be called on each retry'\n          );\n          done();\n        } catch (err) {\n          done(err);\n        }\n      });\n  });\n});\n"
  },
  {
    "path": "test/support/blank.js",
    "content": ""
  },
  {
    "path": "test/support/client.js",
    "content": "const request = require('../..');\n\nif (process.env.HTTP2_TEST) {\n  request.http2 = true;\n}\n\nexports = module.exports = request;\n"
  },
  {
    "path": "test/support/express/index.js",
    "content": "const process = require('process');\nconst express = require('express');\n\nlet http2Request;\nlet http2Res;\nif (process.env.HTTP2_TEST) {\n  const http2 = require('http2');\n  const requestDecorator = require('./requestDecorator');\n  const resDecorator = require('./responseDecorator');\n  http2Request = requestDecorator(\n    Object.create(http2.Http2ServerRequest.prototype)\n  );\n  http2Res = resDecorator(Object.create(http2.Http2ServerResponse.prototype));\n}\n\nfunction createApp() {\n  const app = express();\n  if (process.env.HTTP2_TEST) {\n    app.request = Object.create(http2Request, {\n      app: { configurable: true, enumerable: true, writable: true, value: app }\n    });\n    app.response = Object.create(http2Res, {\n      app: { configurable: true, enumerable: true, writable: true, value: app }\n    });\n  }\n\n  return app;\n}\n\nmodule.exports = createApp;\n"
  },
  {
    "path": "test/support/express/requestDecorator.js",
    "content": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2013 Roman Shtylman\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module dependencies.\n * @private\n */\n\nconst { isIP } = require('net');\nconst accepts = require('accepts');\nconst typeis = require('type-is');\nconst fresh = require('fresh');\nconst parseRange = require('range-parser');\nconst parse = require('parseurl');\nconst proxyaddr = require('proxy-addr');\n\n/**\n * Request prototype.\n * @public\n */\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = setMethods;\n\nfunction setMethods(request) {\n  /**\n   * Return request header.\n   *\n   * The `Referrer` header field is special-cased,\n   * both `Referrer` and `Referer` are interchangeable.\n   *\n   * Examples:\n   *\n   *     req.get('Content-Type');\n   *     // => \"text/plain\"\n   *\n   *     req.get('content-type');\n   *     // => \"text/plain\"\n   *\n   *     req.get('Something');\n   *     // => undefined\n   *\n   * Aliased as `req.header()`.\n   *\n   * @param {String} name\n   * @return {String}\n   * @public\n   */\n\n  request.get = request.header = function header(name) {\n    if (!name) {\n      throw new TypeError('name argument is required to req.get');\n    }\n\n    if (typeof name !== 'string') {\n      throw new TypeError('name must be a string to req.get');\n    }\n\n    const lc = name.toLowerCase();\n\n    switch (lc) {\n      case 'referer':\n      case 'referrer':\n        return this.headers.referrer || this.headers.referer;\n      default:\n        return this.headers[lc];\n    }\n  };\n\n  /**\n   * To do: update docs.\n   *\n   * Check if the given `type(s)` is acceptable, returning\n   * the best match when true, otherwise `undefined`, in which\n   * case you should respond with 406 \"Not Acceptable\".\n   *\n   * The `type` value may be a single MIME type string\n   * such as \"application/json\", an extension name\n   * such as \"json\", a comma-delimited list such as \"json, html, text/plain\",\n   * an argument list such as `\"json\", \"html\", \"text/plain\"`,\n   * or an array `[\"json\", \"html\", \"text/plain\"]`. When a list\n   * or array is given, the _best_ match, if any is returned.\n   *\n   * Examples:\n   *\n   *     // Accept: text/html\n   *     req.accepts('html');\n   *     // => \"html\"\n   *\n   *     // Accept: text/*, application/json\n   *     req.accepts('html');\n   *     // => \"html\"\n   *     req.accepts('text/html');\n   *     // => \"text/html\"\n   *     req.accepts('json, text');\n   *     // => \"json\"\n   *     req.accepts('application/json');\n   *     // => \"application/json\"\n   *\n   *     // Accept: text/*, application/json\n   *     req.accepts('image/png');\n   *     req.accepts('png');\n   *     // => undefined\n   *\n   *     // Accept: text/*;q=.5, application/json\n   *     req.accepts(['html', 'json']);\n   *     req.accepts('html', 'json');\n   *     req.accepts('html, json');\n   *     // => \"json\"\n   *\n   * @param {String|Array} type(s)\n   * @return {String|Array|Boolean}\n   * @public\n   */\n\n  request.accepts = function () {\n    const accept = accepts(this);\n    return accept.types.apply(accept, arguments);\n  };\n\n  /**\n   * Check if the given `encoding`s are accepted.\n   *\n   * @param {String} ...encoding\n   * @return {String|Array}\n   * @public\n   */\n\n  request.acceptsEncodings = function () {\n    const accept = accepts(this);\n    return accept.encodings.apply(accept, arguments);\n  };\n\n  /**\n   * Check if the given `charset`s are acceptable,\n   * otherwise you should respond with 406 \"Not Acceptable\".\n   *\n   * @param {String} ...charset\n   * @return {String|Array}\n   * @public\n   */\n\n  request.acceptsCharsets = function () {\n    const accept = accepts(this);\n    return accept.charsets.apply(accept, arguments);\n  };\n\n  /**\n   * Check if the given `lang`s are acceptable,\n   * otherwise you should respond with 406 \"Not Acceptable\".\n   *\n   * @param {String} ...lang\n   * @return {String|Array}\n   * @public\n   */\n\n  request.acceptsLanguages = function () {\n    const accept = accepts(this);\n    return accept.languages.apply(accept, arguments);\n  };\n\n  /**\n   * Parse Range header field, capping to the given `size`.\n   *\n   * Unspecified ranges such as \"0-\" require knowledge of your resource length. In\n   * the case of a byte range this is of course the total number of bytes. If the\n   * Range header field is not given `undefined` is returned, `-1` when unsatisfiable,\n   * and `-2` when syntactically invalid.\n   *\n   * When ranges are returned, the array has a \"type\" property which is the type of\n   * range that is required (most commonly, \"bytes\"). Each array element is an object\n   * with a \"start\" and \"end\" property for the portion of the range.\n   *\n   * The \"combine\" option can be set to `true` and overlapping & adjacent ranges\n   * will be combined into a single range.\n   *\n   * NOTE: remember that ranges are inclusive, so for example \"Range: users=0-3\"\n   * should respond with 4 users when available, not 3.\n   *\n   * @param {number} size\n   * @param {object} [options]\n   * @param {boolean} [options.combine=false]\n   * @return {number|array}\n   * @public\n   */\n\n  request.range = function range(size, options) {\n    const range = this.get('Range');\n    if (!range) return;\n    return parseRange(size, range, options);\n  };\n\n  /**\n   * Parse the query string of `req.url`.\n   *\n   * This uses the \"query parser\" setting to parse the raw\n   * string into an object.\n   *\n   * @return {String}\n   * @api public\n   */\n\n  defineGetter(request, 'query', function query() {\n    const queryparse = this.app.get('query parser fn');\n\n    if (!queryparse) {\n      // parsing is disabled\n      return Object.create(null);\n    }\n\n    const querystring = parse(this).query;\n\n    return queryparse(querystring);\n  });\n\n  /**\n   * Check if the incoming request contains the \"Content-Type\"\n   * header field, and it contains the give mime `type`.\n   *\n   * Examples:\n   *\n   *      // With Content-Type: text/html; charset=utf-8\n   *      req.is('html');\n   *      req.is('text/html');\n   *      req.is('text/*');\n   *      // => true\n   *\n   *      // When Content-Type is application/json\n   *      req.is('json');\n   *      req.is('application/json');\n   *      req.is('application/*');\n   *      // => true\n   *\n   *      req.is('html');\n   *      // => false\n   *\n   * @param {String|Array} types...\n   * @return {String|false|null}\n   * @public\n   */\n\n  request.is = function is(types) {\n    let array = types;\n\n    // support flattened arguments\n    if (!Array.isArray(types)) {\n      array = Array.from({ length: arguments.length });\n      for (let i = 0; i < array.length; i++) {\n        array[i] = arguments[i];\n      }\n    }\n\n    return typeis(this, array);\n  };\n\n  /**\n   * Return the protocol string \"http\" or \"https\"\n   * when requested with TLS. When the \"trust proxy\"\n   * setting trusts the socket address, the\n   * \"X-Forwarded-Proto\" header field will be trusted\n   * and used if present.\n   *\n   * If you're running behind a reverse proxy that\n   * supplies https for you this may be enabled.\n   *\n   * @return {String}\n   * @public\n   */\n\n  defineGetter(request, 'protocol', function protocol() {\n    const proto = this.connection.encrypted ? 'https' : 'http';\n    const trust = this.app.get('trust proxy fn');\n\n    if (!trust(this.connection.remoteAddress, 0)) {\n      return proto;\n    }\n\n    // Note: X-Forwarded-Proto is normally only ever a\n    //       single value, but this is to be safe.\n    const header = this.get('X-Forwarded-Proto') || proto;\n    const index = header.indexOf(',');\n\n    return index !== -1 ? header.slice(0, index).trim() : header.trim();\n  });\n\n  /**\n   * Short-hand for:\n   *\n   *    req.protocol === 'https'\n   *\n   * @return {Boolean}\n   * @public\n   */\n\n  defineGetter(request, 'secure', function secure() {\n    return this.protocol === 'https';\n  });\n\n  /**\n   * Return the remote address from the trusted proxy.\n   *\n   * The is the remote address on the socket unless\n   * \"trust proxy\" is set.\n   *\n   * @return {String}\n   * @public\n   */\n\n  defineGetter(request, 'ip', function ip() {\n    const trust = this.app.get('trust proxy fn');\n    return proxyaddr(this, trust);\n  });\n\n  /**\n   * When \"trust proxy\" is set, trusted proxy addresses + client.\n   *\n   * For example if the value were \"client, proxy1, proxy2\"\n   * you would receive the array `[\"client\", \"proxy1\", \"proxy2\"]`\n   * where \"proxy2\" is the furthest down-stream and \"proxy1\" and\n   * \"proxy2\" were trusted.\n   *\n   * @return {Array}\n   * @public\n   */\n\n  defineGetter(request, 'ips', function ips() {\n    const trust = this.app.get('trust proxy fn');\n    const addrs = proxyaddr.all(this, trust);\n\n    // reverse the order (to farthest -> closest)\n    // and remove socket address\n    addrs.reverse().pop();\n\n    return addrs;\n  });\n\n  /**\n   * Return subdomains as an array.\n   *\n   * Subdomains are the dot-separated parts of the host before the main domain of\n   * the app. By default, the domain of the app is assumed to be the last two\n   * parts of the host. This can be changed by setting \"subdomain offset\".\n   *\n   * For example, if the domain is \"tobi.ferrets.example.com\":\n   * If \"subdomain offset\" is not set, req.subdomains is `[\"ferrets\", \"tobi\"]`.\n   * If \"subdomain offset\" is 3, req.subdomains is `[\"tobi\"]`.\n   *\n   * @return {Array}\n   * @public\n   */\n\n  defineGetter(request, 'subdomains', function subdomains() {\n    const { hostname } = this;\n\n    if (!hostname) return [];\n\n    const offset = this.app.get('subdomain offset');\n    const subdomains = !isIP(hostname)\n      ? hostname.split('.').reverse()\n      : [hostname];\n\n    return subdomains.slice(offset);\n  });\n\n  /**\n   * Short-hand for `url.parse(req.url).pathname`.\n   *\n   * @return {String}\n   * @public\n   */\n\n  defineGetter(request, 'path', function path() {\n    return parse(this).pathname;\n  });\n\n  /**\n   * Parse the \"Host\" header field to a host.\n   *\n   * When the \"trust proxy\" setting trusts the socket\n   * address, the \"X-Forwarded-Host\" header field will\n   * be trusted.\n   *\n   * @return {String}\n   * @public\n   */\n\n  defineGetter(request, 'host', function host() {\n    const trust = this.app.get('trust proxy fn');\n    let value = this.get('X-Forwarded-Host');\n\n    if (!value || !trust(this.connection.remoteAddress, 0)) {\n      value = this.get('Host');\n    }\n\n    return value || undefined;\n  });\n\n  /**\n   * Parse the \"Host\" header field to a hostname.\n   *\n   * When the \"trust proxy\" setting trusts the socket\n   * address, the \"X-Forwarded-Host\" header field will\n   * be trusted.\n   *\n   * @return {String}\n   * @api public\n   */\n\n  defineGetter(request, 'hostname', function hostname() {\n    const { host } = this;\n\n    if (!host) return;\n\n    // IPv6 literal support\n    const offset = host[0] === '[' ? host.indexOf(']') + 1 : 0;\n    const index = host.indexOf(':', offset);\n\n    return index !== -1 ? host.slice(0, index) : host;\n  });\n\n  /**\n   * Check if the request is fresh, aka\n   * Last-Modified and/or the ETag\n   * still match.\n   *\n   * @return {Boolean}\n   * @public\n   */\n\n  defineGetter(request, 'fresh', function () {\n    const { method } = this;\n    const { res } = this;\n    const status = res.statusCode;\n\n    // GET or HEAD for weak freshness validation only\n    if (method !== 'GET' && method !== 'HEAD') return false;\n\n    // 2xx or 304 as per rfc2616 14.26\n    if ((status >= 200 && status < 300) || status === 304) {\n      return fresh(this.headers, {\n        etag: res.get('ETag'),\n        'last-modified': res.get('Last-Modified')\n      });\n    }\n\n    return false;\n  });\n\n  /**\n   * Check if the request is stale, aka\n   * \"Last-Modified\" and / or the \"ETag\" for the\n   * resource has changed.\n   *\n   * @return {Boolean}\n   * @public\n   */\n\n  defineGetter(request, 'stale', function stale() {\n    return !this.fresh;\n  });\n\n  /**\n   * Check if the request was an _XMLHttpRequest_.\n   *\n   * @return {Boolean}\n   * @public\n   */\n\n  defineGetter(request, 'xhr', function xhr() {\n    const value = this.get('X-Requested-With') || '';\n    return value.toLowerCase() === 'xmlhttprequest';\n  });\n\n  return request;\n}\n\n/**\n * Helper function for creating a getter on an object.\n *\n * @param {Object} obj\n * @param {String} name\n * @param {Function} getter\n * @private\n */\nfunction defineGetter(object, name, getter) {\n  Object.defineProperty(object, name, {\n    configurable: true,\n    enumerable: true,\n    get: getter\n  });\n}\n"
  },
  {
    "path": "test/support/express/responseDecorator.js",
    "content": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module dependencies.\n * @private\n */\n\nconst path = require('path');\nconst { Buffer } = require('safe-buffer');\nconst contentDisposition = require('content-disposition');\nconst encodeUrl = require('encodeurl');\nconst escapeHtml = require('escape-html');\nconst onFinished = require('on-finished');\nconst pathIsAbsolute = require('path-is-absolute');\nconst statuses = require('statuses');\nconst merge = require('utils-merge');\nconst { sign } = require('cookie-signature');\nconst cookie = require('cookie');\nconst send = require('send');\nconst { normalizeType } = require('./utils');\nconst { normalizeTypes } = require('./utils');\nconst { setCharset } = require('./utils');\n\nconst { extname } = path;\nconst { mime } = send;\nconst { resolve } = path;\nconst vary = require('vary');\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = setMethods;\n\nfunction setMethods(res) {\n  /**\n   * Module variables.\n   * @private\n   */\n\n  const charsetRegExp = /;\\s*charset\\s*=/;\n\n  /**\n   * Set status `code`.\n   *\n   * @param {Number} code\n   * @return {ServerResponse}\n   * @public\n   */\n\n  res.status = function status(code) {\n    this.statusCode = code;\n    return this;\n  };\n\n  /**\n   * Set Link header field with the given `links`.\n   *\n   * Examples:\n   *\n   *    res.links({\n   *      next: 'http://api.example.com/users?page=2',\n   *      last: 'http://api.example.com/users?page=5'\n   *    });\n   *\n   * @param {Object} links\n   * @return {ServerResponse}\n   * @public\n   */\n\n  res.links = function (links) {\n    let link = this.get('Link') || '';\n    if (link) link += ', ';\n    return this.set(\n      'Link',\n      link +\n        Object.keys(links)\n          .map((rel) => {\n            return '<' + links[rel] + '>; rel=\"' + rel + '\"';\n          })\n          .join(', ')\n    );\n  };\n\n  /**\n   * Send a response.\n   *\n   * Examples:\n   *\n   *     res.send(Buffer.from('wahoo'));\n   *     res.send({ some: 'json' });\n   *     res.send('<p>some html</p>');\n   *\n   * @param {string|number|boolean|object|Buffer} body\n   * @public\n   */\n\n  res.send = function send(body) {\n    let chunk = body;\n    let encoding;\n    const { req } = this;\n    let type;\n\n    // settings\n    const { app } = this;\n\n    switch (typeof chunk) {\n      // string defaulting to html\n      case 'string':\n        if (!this.get('Content-Type')) {\n          this.type('html');\n        }\n\n        break;\n      case 'boolean':\n      case 'number':\n      case 'object':\n        if (chunk === null) {\n          chunk = '';\n        } else if (Buffer.isBuffer(chunk)) {\n          if (!this.get('Content-Type')) {\n            this.type('bin');\n          }\n        } else {\n          return this.json(chunk);\n        }\n\n        break;\n    }\n\n    // write strings in utf-8\n    if (typeof chunk === 'string') {\n      encoding = 'utf8';\n      type = this.get('Content-Type');\n\n      // reflect this in content-type\n      if (typeof type === 'string') {\n        this.set('Content-Type', setCharset(type, 'utf-8'));\n      }\n    }\n\n    // determine if ETag should be generated\n    const etagFn = app.get('etag fn');\n    const generateETag = !this.get('ETag') && typeof etagFn === 'function';\n\n    // populate Content-Length\n    let length_;\n    if (chunk !== undefined) {\n      if (Buffer.isBuffer(chunk)) {\n        // get length of Buffer\n        length_ = chunk.length;\n      } else if (!generateETag && chunk.length < 1000) {\n        // just calculate length when no ETag + small chunk\n        length_ = Buffer.byteLength(chunk, encoding);\n      } else {\n        // convert chunk to Buffer and calculate\n        chunk = Buffer.from(chunk, encoding);\n        encoding = undefined;\n        length_ = chunk.length;\n      }\n\n      this.set('Content-Length', length_);\n    }\n\n    // populate ETag\n    let etag;\n    if (\n      generateETag &&\n      length_ !== undefined &&\n      (etag = etagFn(chunk, encoding))\n    ) {\n      this.set('ETag', etag);\n    }\n\n    // freshness\n    if (req.fresh) this.statusCode = 304;\n\n    // strip irrelevant headers\n    if (this.statusCode === 204 || this.statusCode === 304) {\n      this.removeHeader('Content-Type');\n      this.removeHeader('Content-Length');\n      this.removeHeader('Transfer-Encoding');\n      chunk = '';\n    }\n\n    if (req.method === 'HEAD') {\n      // skip body for HEAD\n      this.end();\n    } else {\n      // respond\n      this.end(chunk, encoding);\n    }\n\n    return this;\n  };\n\n  /**\n   * Send JSON response.\n   *\n   * Examples:\n   *\n   *     res.json(null);\n   *     res.json({ user: 'tj' });\n   *\n   * @param {string|number|boolean|object} obj\n   * @public\n   */\n\n  res.json = function json(object) {\n    // settings\n    const { app } = this;\n    const escape = app.get('json escape');\n    const replacer = app.get('json replacer');\n    const spaces = app.get('json spaces');\n    const body = stringify(object, replacer, spaces, escape);\n\n    // content-type\n    if (!this.get('Content-Type')) {\n      this.set('Content-Type', 'application/json');\n    }\n\n    return this.send(body);\n  };\n\n  /**\n   * Send JSON response with JSONP callback support.\n   *\n   * Examples:\n   *\n   *     res.jsonp(null);\n   *     res.jsonp({ user: 'tj' });\n   *\n   * @param {string|number|boolean|object} obj\n   * @public\n   */\n\n  res.jsonp = function jsonp(object) {\n    // settings\n    const { app } = this;\n    const escape = app.get('json escape');\n    const replacer = app.get('json replacer');\n    const spaces = app.get('json spaces');\n    let body = stringify(object, replacer, spaces, escape);\n    let callback = this.req.query[app.get('jsonp callback name')];\n\n    // content-type\n    if (!this.get('Content-Type')) {\n      this.set('X-Content-Type-Options', 'nosniff');\n      this.set('Content-Type', 'application/json');\n    }\n\n    // fixup callback\n    if (Array.isArray(callback)) {\n      callback = callback[0];\n    }\n\n    // jsonp\n    if (typeof callback === 'string' && callback.length > 0) {\n      this.set('X-Content-Type-Options', 'nosniff');\n      this.set('Content-Type', 'text/javascript');\n\n      // restrict callback charset\n      callback = callback.replace(/[^[\\]\\w$.]/g, '');\n\n      // replace chars not allowed in JavaScript that are in JSON\n      body = body.replace(/\\u2028/g, '\\\\u2028').replace(/\\u2029/g, '\\\\u2029');\n\n      // the /**/ is a specific security mitigation for \"Rosetta Flash JSONP abuse\"\n      // the typeof check is just to reduce client error noise\n      body =\n        '/**/ typeof ' +\n        callback +\n        \" === 'function' && \" +\n        callback +\n        '(' +\n        body +\n        ');';\n    }\n\n    return this.send(body);\n  };\n\n  /**\n   * Send given HTTP status code.\n   *\n   * Sets the response status to `statusCode` and the body of the\n   * response to the standard description from node's http.STATUS_CODES\n   * or the statusCode number if no description.\n   *\n   * Examples:\n   *\n   *     res.sendStatus(200);\n   *\n   * @param {number} statusCode\n   * @public\n   */\n\n  res.sendStatus = function sendStatus(statusCode) {\n    const body = statuses(statusCode) || String(statusCode);\n\n    this.statusCode = statusCode;\n    this.type('txt');\n\n    return this.send(body);\n  };\n\n  /**\n   * Transfer the file at the given `path`.\n   *\n   * Automatically sets the _Content-Type_ response header field.\n   * The callback `callback(err)` is invoked when the transfer is complete\n   * or when an error occurs. Be sure to check `res.sentHeader`\n   * if you wish to attempt responding, as the header and some data\n   * may have already been transferred.\n   *\n   * Options:\n   *\n   *   - `maxAge`   defaulting to 0 (can be string converted by `ms`)\n   *   - `root`     root directory for relative filenames\n   *   - `headers`  object of headers to serve with file\n   *   - `dotfiles` serve dotfiles, defaulting to false; can be `\"allow\"` to send them\n   *\n   * Other options are passed along to `send`.\n   *\n   * Examples:\n   *\n   *  The following example illustrates how `res.sendFile()` may\n   *  be used as an alternative for the `static()` middleware for\n   *  dynamic situations. The code backing `res.sendFile()` is actually\n   *  the same code, so HTTP cache support etc is identical.\n   *\n   *     app.get('/user/:uid/photos/:file', function(req, res){\n   *       var uid = req.params.uid\n   *         , file = req.params.file;\n   *\n   *       req.user.mayViewFilesFrom(uid, function(yes){\n   *         if (yes) {\n   *           res.sendFile('/uploads/' + uid + '/' + file);\n   *         } else {\n   *           res.send(403, 'Sorry! you cant see that.');\n   *         }\n   *       });\n   *     });\n   *\n   * @public\n   */\n\n  res.sendFile = function sendFile(path, options, callback) {\n    let done = callback;\n    const { req } = this;\n    const res = this;\n    const { next } = req;\n    let options_ = options || {};\n\n    if (!path) {\n      throw new TypeError('path argument is required to res.sendFile');\n    }\n\n    // support function as second arg\n    if (typeof options === 'function') {\n      done = options;\n      options_ = {};\n    }\n\n    if (!options_.root && !pathIsAbsolute(path)) {\n      throw new TypeError(\n        'path must be absolute or specify root to res.sendFile'\n      );\n    }\n\n    // create file stream\n    const pathname = encodeURI(path);\n    const file = send(req, pathname, options_);\n\n    // transfer\n    sendfile(res, file, options_, (error) => {\n      if (done) return done(error);\n      if (error && error.code === 'EISDIR') return next();\n\n      // next() all but write errors\n      if (error && error.code !== 'ECONNABORTED' && error.syscall !== 'write') {\n        next(error);\n      }\n    });\n  };\n\n  /**\n   * Transfer the file at the given `path` as an attachment.\n   *\n   * Optionally providing an alternate attachment `filename`,\n   * and optional callback `callback(err)`. The callback is invoked\n   * when the data transfer is complete, or when an error has\n   * ocurred. Be sure to check `res.headersSent` if you plan to respond.\n   *\n   * Optionally providing an `options` object to use with `res.sendFile()`.\n   * This function will set the `Content-Disposition` header, overriding\n   * any `Content-Disposition` header passed as header options in order\n   * to set the attachment and filename.\n   *\n   * This method uses `res.sendFile()`.\n   *\n   * @public\n   */\n\n  res.download = function download(path, filename, options, callback) {\n    let done = callback;\n    let name = filename;\n    let options_ = options || null;\n\n    // support function as second or third arg\n    if (typeof filename === 'function') {\n      done = filename;\n      name = null;\n      options_ = null;\n    } else if (typeof options === 'function') {\n      done = options;\n      options_ = null;\n    }\n\n    // set Content-Disposition when file is sent\n    const headers = {\n      'Content-Disposition': contentDisposition(name || path)\n    };\n\n    // merge user-provided headers\n    if (options_ && options_.headers) {\n      const keys = Object.keys(options_.headers);\n      for (const key of keys) {\n        if (key.toLowerCase() !== 'content-disposition') {\n          headers[key] = options_.headers[key];\n        }\n      }\n    }\n\n    // merge user-provided options\n    options_ = Object.create(options_);\n    options_.headers = headers;\n\n    // Resolve the full path for sendFile\n    const fullPath = resolve(path);\n\n    // send file\n    return this.sendFile(fullPath, options_, done);\n  };\n\n  /**\n   * Set _Content-Type_ response header with `type` through `mime.lookup()`\n   * when it does not contain \"/\", or set the Content-Type to `type` otherwise.\n   *\n   * Examples:\n   *\n   *     res.type('.html');\n   *     res.type('html');\n   *     res.type('json');\n   *     res.type('application/json');\n   *     res.type('png');\n   *\n   * @param {String} type\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.contentType = res.type = function contentType(type) {\n    const ct = !type.includes('/') ? mime.lookup(type) : type;\n\n    return this.set('Content-Type', ct);\n  };\n\n  /**\n   * Respond to the Acceptable formats using an `obj`\n   * of mime-type callbacks.\n   *\n   * This method uses `req.accepted`, an array of\n   * acceptable types ordered by their quality values.\n   * When \"Accept\" is not present the _first_ callback\n   * is invoked, otherwise the first match is used. When\n   * no match is performed the server responds with\n   * 406 \"Not Acceptable\".\n   *\n   * Content-Type is set for you, however if you choose\n   * you may alter this within the callback using `res.type()`\n   * or `res.set('Content-Type', ...)`.\n   *\n   *    res.format({\n   *      'text/plain': function(){\n   *        res.send('hey');\n   *      },\n   *\n   *      'text/html': function(){\n   *        res.send('<p>hey</p>');\n   *      },\n   *\n   *      'appliation/json': function(){\n   *        res.send({ message: 'hey' });\n   *      }\n   *    });\n   *\n   * In addition to canonicalized MIME types you may\n   * also use extnames mapped to these types:\n   *\n   *    res.format({\n   *      text: function(){\n   *        res.send('hey');\n   *      },\n   *\n   *      html: function(){\n   *        res.send('<p>hey</p>');\n   *      },\n   *\n   *      json: function(){\n   *        res.send({ message: 'hey' });\n   *      }\n   *    });\n   *\n   * By default Express passes an `Error`\n   * with a `.status` of 406 to `next(err)`\n   * if a match is not made. If you provide\n   * a `.default` callback it will be invoked\n   * instead.\n   *\n   * @param {Object} obj\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.format = function (object) {\n    const { req } = this;\n    const { next } = req;\n\n    const fn = object.default;\n    if (fn) delete object.default;\n    const keys = Object.keys(object);\n\n    const key = keys.length > 0 ? req.accepts(keys) : false;\n\n    this.vary('Accept');\n\n    if (key) {\n      this.set('Content-Type', normalizeType(key).value);\n      object[key](req, this, next);\n    } else if (fn) {\n      fn();\n    } else {\n      const error = new Error('Not Acceptable');\n      error.status = error.statusCode = 406;\n      error.types = normalizeTypes(keys).map((o) => {\n        return o.value;\n      });\n      next(error);\n    }\n\n    return this;\n  };\n\n  /**\n   * Set _Content-Disposition_ header to _attachment_ with optional `filename`.\n   *\n   * @param {String} filename\n   * @return {ServerResponse}\n   * @public\n   */\n\n  res.attachment = function attachment(filename) {\n    if (filename) {\n      this.type(extname(filename));\n    }\n\n    this.set('Content-Disposition', contentDisposition(filename));\n\n    return this;\n  };\n\n  /**\n   * Append additional header `field` with value `val`.\n   *\n   * Example:\n   *\n   *    res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>']);\n   *    res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly');\n   *    res.append('Warning', '199 Miscellaneous warning');\n   *\n   * @param {String} field\n   * @param {String|Array} val\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.append = function append(field, value_) {\n    const previous = this.get(field);\n    let value = value_;\n\n    if (previous) {\n      // concat the new and prev vals\n      value = Array.isArray(previous)\n        ? previous.concat(value_)\n        : Array.isArray(value_)\n        ? [previous].concat(value_)\n        : [previous, value_];\n    }\n\n    return this.set(field, value);\n  };\n\n  /**\n   * Set header `field` to `val`, or pass\n   * an object of header fields.\n   *\n   * Examples:\n   *\n   *    res.set('Foo', ['bar', 'baz']);\n   *    res.set('Accept', 'application/json');\n   *    res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });\n   *\n   * Aliased as `res.header()`.\n   *\n   * @param {String|Object} field\n   * @param {String|Array} val\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.set = res.header = function header(field, value_) {\n    if (arguments.length === 2) {\n      let value = Array.isArray(value_) ? value_.map(String) : String(value_);\n\n      // add charset to content-type\n      if (field.toLowerCase() === 'content-type') {\n        if (Array.isArray(value)) {\n          throw new TypeError('Content-Type cannot be set to an Array');\n        }\n\n        if (!charsetRegExp.test(value)) {\n          const charset = mime.charsets.lookup(value.split(';')[0]);\n          if (charset) value += '; charset=' + charset.toLowerCase();\n        }\n      }\n\n      this.setHeader(field, value);\n    } else {\n      for (const key in field) {\n        this.set(key, field[key]);\n      }\n    }\n\n    return this;\n  };\n\n  /**\n   * Get value for header `field`.\n   *\n   * @param {String} field\n   * @return {String}\n   * @public\n   */\n\n  res.get = function (field) {\n    return this.getHeader(field);\n  };\n\n  /**\n   * Clear cookie `name`.\n   *\n   * @param {String} name\n   * @param {Object} [options]\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.clearCookie = function clearCookie(name, options) {\n    const options_ = merge({ expires: new Date(1), path: '/' }, options);\n\n    return this.cookie(name, '', options_);\n  };\n\n  /**\n   * Set cookie `name` to `value`, with the given `options`.\n   *\n   * Options:\n   *\n   *    - `maxAge`   max-age in milliseconds, converted to `expires`\n   *    - `signed`   sign the cookie\n   *    - `path`     defaults to \"/\"\n   *\n   * Examples:\n   *\n   *    // \"Remember Me\" for 15 minutes\n   *    res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });\n   *\n   *    // save as above\n   *    res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })\n   *\n   * @param {String} name\n   * @param {String|Object} value\n   * @param {Object} [options]\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.cookie = function (name, value, options) {\n    const options_ = merge({}, options);\n    const { secret } = this.req;\n    const { signed } = options_;\n\n    if (signed && !secret) {\n      throw new Error('cookieParser(\"secret\") required for signed cookies');\n    }\n\n    let value_ =\n      typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value);\n\n    if (signed) {\n      value_ = 's:' + sign(value_, secret);\n    }\n\n    if ('maxAge' in options_) {\n      options_.expires = new Date(Date.now() + options_.maxAge);\n      options_.maxAge /= 1000;\n    }\n\n    if (options_.path == null) {\n      options_.path = '/';\n    }\n\n    this.append('Set-Cookie', cookie.serialize(name, String(value_), options_));\n\n    return this;\n  };\n\n  /**\n   * Set the location header to `url`.\n   *\n   * The given `url` can also be \"back\", which redirects\n   * to the _Referrer_ or _Referer_ headers or \"/\".\n   *\n   * Examples:\n   *\n   *    res.location('/foo/bar').;\n   *    res.location('http://example.com');\n   *    res.location('../login');\n   *\n   * @param {String} url\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.location = function location(url) {\n    let loc = url;\n\n    // \"back\" is an alias for the referrer\n    if (url === 'back') {\n      loc = this.req.get('Referrer') || '/';\n    }\n\n    // set location\n    return this.set('Location', encodeUrl(loc));\n  };\n\n  /**\n   * Redirect to the given `url` with optional response `status`\n   * defaulting to 302.\n   *\n   * The resulting `url` is determined by `res.location()`, so\n   * it will play nicely with mounted apps, relative paths,\n   * `\"back\"` etc.\n   *\n   * Examples:\n   *\n   *    res.redirect('/foo/bar');\n   *    res.redirect('http://example.com');\n   *    res.redirect(301, 'http://example.com');\n   *    res.redirect('../login'); // /blog/post/1 -> /blog/login\n   *\n   * @public\n   */\n\n  res.redirect = function redirect(url) {\n    let address = url;\n    let body;\n    let status = 302;\n\n    // allow status / url\n    if (arguments.length === 2) {\n      status = arguments[0];\n      address = arguments[1];\n    }\n\n    // Set location header\n    address = this.location(address).get('Location');\n\n    // Support text/{plain,html} by default\n    this.format({\n      text() {\n        body = statuses(status) + '. Redirecting to ' + address;\n      },\n\n      html() {\n        const u = escapeHtml(address);\n        body =\n          '<p>' +\n          statuses(status) +\n          '. Redirecting to <a href=\"' +\n          u +\n          '\">' +\n          u +\n          '</a></p>';\n      },\n\n      default() {\n        body = '';\n      }\n    });\n\n    // Respond\n    this.statusCode = status;\n    this.set('Content-Length', Buffer.byteLength(body));\n\n    if (this.req.method === 'HEAD') {\n      this.end();\n    } else {\n      this.end(body);\n    }\n  };\n\n  /**\n   * Add `field` to Vary. If already present in the Vary set, then\n   * this call is simply ignored.\n   *\n   * @param {Array|String} field\n   * @return {ServerResponse} for chaining\n   * @public\n   */\n\n  res.vary = function (field) {\n    vary(this, field);\n\n    return this;\n  };\n\n  /**\n   * Render `view` with the given `options` and optional callback `fn`.\n   * When a callback function is given a response will _not_ be made\n   * automatically, otherwise a response of _200_ and _text/html_ is given.\n   *\n   * Options:\n   *\n   *  - `cache`     boolean hinting to the engine it should cache\n   *  - `filename`  filename of the view being rendered\n   *\n   * @public\n   */\n\n  res.render = function render(view, options, callback) {\n    const { app } = this.req;\n    let done = callback;\n    let options_ = options || {};\n    const { req } = this;\n    const self = this;\n\n    // support callback function as second arg\n    if (typeof options === 'function') {\n      done = options;\n      options_ = {};\n    }\n\n    // merge res.locals\n    options_._locals = self.locals;\n\n    // default callback to respond\n    done =\n      done ||\n      function (error, string_) {\n        if (error) return req.next(error);\n        self.send(string_);\n      };\n\n    // render\n    app.render(view, options_, done);\n  };\n\n  // pipe the send file stream\n  function sendfile(res, file, options, callback) {\n    let done = false;\n    let streaming;\n\n    // request aborted\n    function onaborted() {\n      if (done) return;\n      done = true;\n\n      const error = new Error('Request aborted');\n      error.code = 'ECONNABORTED';\n      callback(error);\n    }\n\n    // directory\n    function ondirectory() {\n      if (done) return;\n      done = true;\n\n      const error = new Error('EISDIR, read');\n      error.code = 'EISDIR';\n      callback(error);\n    }\n\n    // errors\n    function onerror(error) {\n      if (done) return;\n      done = true;\n      callback(error);\n    }\n\n    // ended\n    function onend() {\n      if (done) return;\n      done = true;\n      callback();\n    }\n\n    // file\n    function onfile() {\n      streaming = false;\n    }\n\n    // finished\n    function onfinish(error) {\n      if (error && error.code === 'ECONNRESET') return onaborted();\n      if (error) return onerror(error);\n      if (done) return;\n\n      setImmediate(() => {\n        if (streaming !== false && !done) {\n          onaborted();\n          return;\n        }\n\n        if (done) return;\n        done = true;\n        callback();\n      });\n    }\n\n    // streaming\n    function onstream() {\n      streaming = true;\n    }\n\n    file.on('directory', ondirectory);\n    file.on('end', onend);\n    file.on('error', onerror);\n    file.on('file', onfile);\n    file.on('stream', onstream);\n\n    if (options.headers) {\n      // set headers on successful transfer\n      file.on('headers', function headers(res) {\n        const object = options.headers;\n        const keys = Object.keys(object);\n\n        for (const k of keys) {\n          res.setHeader(k, object[k]);\n        }\n      });\n    }\n\n    // pipe\n    file.pipe(res);\n\n    onFinished(res, onfinish);\n  }\n\n  return res;\n}\n\n/**\n * Stringify JSON, like JSON.stringify, but v8 optimized, with the\n * ability to escape characters that can trigger HTML sniffing.\n *\n * @param {*} value\n * @param {function} replaces\n * @param {number} spaces\n * @param {boolean} escape\n * @returns {string}\n * @private\n */\n\nfunction stringify(value, replacer, spaces, escape) {\n  // v8 checks arguments.length for optimizing simple call\n  // https://bugs.chromium.org/p/v8/issues/detail?id=4730\n  let json =\n    replacer || spaces\n      ? JSON.stringify(value, replacer, spaces)\n      : JSON.stringify(value);\n\n  if (escape) {\n    json = json.replace(/[<>&]/g, (c) => {\n      switch (c.charCodeAt(0)) {\n        case 0x3c:\n          return '\\\\u003c';\n        case 0x3e:\n          return '\\\\u003e';\n        case 0x26:\n          return '\\\\u0026';\n        default:\n          return c;\n      }\n    });\n  }\n\n  return json;\n}\n"
  },
  {
    "path": "test/support/express/utils.js",
    "content": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module dependencies.\n * @api private\n */\n\nconst querystring = require('querystring');\nconst { Buffer } = require('safe-buffer');\nconst contentType = require('content-type');\nconst { mime } = require('send');\nconst etag = require('etag');\nconst proxyaddr = require('proxy-addr');\nconst qs = require('qs');\n\nlet isHttp2Supported = true;\n\n/**\n * Test for http2 support\n * @api private\n */\ntry {\n  require('http2');\n} catch {\n  isHttp2Supported = false;\n}\n/**\n * Return strong ETag for `body`.\n *\n * @param {String|Buffer} body\n * @param {String} [encoding]\n * @return {String}\n * @api private\n */\n\nexports.etag = createETagGenerator({ weak: false });\n\n/**\n * Return weak ETag for `body`.\n *\n * @param {String|Buffer} body\n * @param {String} [encoding]\n * @return {String}\n * @api private\n */\n\nexports.wetag = createETagGenerator({ weak: true });\n\n/**\n * Normalize the given `type`, for example \"html\" becomes \"text/html\".\n *\n * @param {String} type\n * @return {Object}\n * @api private\n */\n\nexports.normalizeType = function (type) {\n  return ~type.indexOf('/')\n    ? acceptParameters(type)\n    : { value: mime.lookup(type), params: {} };\n};\n\n/**\n * Normalize `types`, for example \"html\" becomes \"text/html\".\n *\n * @param {Array} types\n * @return {Array}\n * @api private\n */\n\nexports.normalizeTypes = function (types) {\n  const returnValue = [];\n\n  for (const element of types) {\n    returnValue.push(exports.normalizeType(element));\n  }\n\n  return returnValue;\n};\n\n/**\n * Parse accept params `str` returning an\n * object with `.value`, `.quality` and `.params`.\n * also includes `.originalIndex` for stable sorting\n *\n * @param {String} str\n * @return {Object}\n * @api private\n */\n\nfunction acceptParameters(string_, index) {\n  const parts = string_.split(/ *; */);\n  const returnValue = {\n    value: parts[0],\n    quality: 1,\n    params: {},\n    originalIndex: index\n  };\n\n  for (let i = 1; i < parts.length; ++i) {\n    const pms = parts[i].split(/ *= */);\n    if (pms[0] === 'q') {\n      returnValue.quality = Number.parseFloat(pms[1]);\n    } else {\n      returnValue.params[pms[0]] = pms[1];\n    }\n  }\n\n  return returnValue;\n}\n\n/**\n * Compile \"etag\" value to function.\n *\n * @param  {Boolean|String|Function} val\n * @return {Function}\n * @api private\n */\n\nexports.compileETag = function (value) {\n  let fn;\n\n  if (typeof value === 'function') {\n    return value;\n  }\n\n  switch (value) {\n    case true:\n      fn = exports.wetag;\n      break;\n    case false:\n      break;\n    case 'strong':\n      fn = exports.etag;\n      break;\n    case 'weak':\n      fn = exports.wetag;\n      break;\n    default:\n      throw new TypeError('unknown value for etag function: ' + value);\n  }\n\n  return fn;\n};\n\n/**\n * Compile \"query parser\" value to function.\n *\n * @param  {String|Function} val\n * @return {Function}\n * @api private\n */\n\nexports.compileQueryParser = function compileQueryParser(value) {\n  let fn;\n\n  if (typeof value === 'function') {\n    return value;\n  }\n\n  switch (value) {\n    case true:\n      fn = querystring.parse;\n      break;\n    case false:\n      break;\n    case 'extended':\n      fn = parseExtendedQueryString;\n      break;\n    case 'simple':\n      fn = querystring.parse;\n      break;\n    default:\n      throw new TypeError('unknown value for query parser function: ' + value);\n  }\n\n  return fn;\n};\n\n/**\n * Compile \"proxy trust\" value to function.\n *\n * @param  {Boolean|String|Number|Array|Function} val\n * @return {Function}\n * @api private\n */\n\nexports.compileTrust = function (value) {\n  if (typeof value === 'function') return value;\n\n  if (value === true) {\n    // Support plain true/false\n    return function () {\n      return true;\n    };\n  }\n\n  if (typeof value === 'number') {\n    // Support trusting hop count\n    return function (a, i) {\n      return i < value;\n    };\n  }\n\n  if (typeof value === 'string') {\n    // Support comma-separated values\n    value = value.split(/ *, */);\n  }\n\n  return proxyaddr.compile(value || []);\n};\n\n/**\n * Flag for http2 support\n */\nexports.isHttp2Supported = isHttp2Supported;\n/**\n * Set the charset in a given Content-Type string.\n *\n * @param {String} type\n * @param {String} charset\n * @return {String}\n * @api private\n */\n\nexports.setCharset = function setCharset(type, charset) {\n  if (!type || !charset) {\n    return type;\n  }\n\n  // parse type\n  const parsed = contentType.parse(type);\n\n  // set charset\n  parsed.parameters.charset = charset;\n\n  // format type\n  return contentType.format(parsed);\n};\n\n/**\n * Create an ETag generator function, generating ETags with\n * the given options.\n *\n * @param {object} options\n * @return {function}\n * @private\n */\n\nfunction createETagGenerator(options) {\n  return function generateETag(body, encoding) {\n    const buf = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body;\n\n    return etag(buf, options);\n  };\n}\n\n/**\n * Parse an extended query string with qs.\n *\n * @return {Object}\n * @private\n */\n\nfunction parseExtendedQueryString(string_) {\n  return qs.parse(string_, {\n    allowPrototypes: true\n  });\n}\n"
  },
  {
    "path": "test/support/server.js",
    "content": "const fs = require('node:fs');\nconst path = require('node:path');\nconst process = require('node:process');\nconst { Buffer } = require('node:buffer');\nlet http = require('node:http');\nconst multer = require('multer');\nconst bodyParser = require('body-parser');\nconst cookieParser = require('cookie-parser');\nconst basicAuth = require('basic-auth-connect');\nconst express = require('./express');\n\nlet isPseudoHeader;\n\nif (process.env.HTTP2_TEST) {\n  http = require('node:http2');\n  const {\n    HTTP2_HEADER_AUTHORITY,\n    HTTP2_HEADER_METHOD,\n    HTTP2_HEADER_PATH,\n    HTTP2_HEADER_SCHEME,\n    HTTP2_HEADER_STATUS\n  } = http.constants;\n  isPseudoHeader = function (name) {\n    switch (name) {\n      case HTTP2_HEADER_STATUS: // :status\n      case HTTP2_HEADER_METHOD: // :method\n      case HTTP2_HEADER_PATH: // :path\n      case HTTP2_HEADER_AUTHORITY: // :authority\n      case HTTP2_HEADER_SCHEME: {\n        // :scheme\n        return true;\n      }\n\n      default: {\n        return false;\n      }\n    }\n  };\n}\n\nconst app = express();\n\napp.use((request, res, next) => {\n  res.set('Cache-Control', 'no-cache, no-store');\n  next();\n});\n\napp.all('/url', (request, res) => {\n  res.send(request.url);\n});\n\napp.all('/echo', (request, res) => {\n  const { headers } = request;\n  if (process.env.HTTP2_TEST) {\n    for (const name of Object.keys(headers)) {\n      if (isPseudoHeader(name)) {\n        delete headers[name];\n      }\n    }\n  }\n\n  res.writeHead(200, headers);\n  request.pipe(res);\n});\n\nlet uniq = 0;\napp.all('/unique', (request, res) => {\n  res.send(`never the same ${uniq++}`);\n});\n\napp.use(bodyParser.urlencoded({ extended: true }));\napp.use(multer().none());\n\napp.all('/formecho', (request, res) => {\n  if (\n    !/application\\/x-www-form-urlencoded|multipart\\/form-data/.test(\n      request.headers['content-type']\n    )\n  ) {\n    return res.status(400).end('wrong type');\n  }\n\n  res.json(request.body);\n});\n\napp.use(bodyParser.json());\napp.use(cookieParser());\n\napp.use('/xdomain', (request, res, next) => {\n  if (!request.get('Origin')) return next();\n  res.set('Access-Control-Allow-Origin', request.get('Origin'));\n  res.set('Access-Control-Allow-Credentials', 'true');\n  res.set('Access-Control-Allow-Methods', 'POST');\n  res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');\n  if (request.method === 'OPTIONS') return res.send(200);\n  next();\n});\n\napp.get('/xdomain', (request, res) => {\n  res.send('tobi');\n});\n\napp.get('/login', (request, res) => {\n  res.status(200).send('<form id=\"login\"></form>');\n});\n\napp.get('/json', (request, res) => {\n  res.status(200).json({ name: 'manny' });\n});\n\napp.get('/json-hal', (request, res) => {\n  res.set('content-type', 'application/hal+json');\n  res.send({ name: 'hal 5000' });\n});\n\napp.get('/ok', (request, res) => {\n  res.send('ok');\n});\n\napp.get('/foo', (request, res) => {\n  res\n    .header('Content-Type', 'application/x-www-form-urlencoded')\n    .send('foo=bar');\n});\n\napp.get('/form-data', (request, res) => {\n  res.header('Content-Type', 'application/x-www-form-urlencoded');\n  res.send('pet[name]=manny');\n});\n\napp.post('/movie', (request, res) => {\n  res.redirect('/movies/all/0');\n});\n\napp.get('/', (request, res) => {\n  res.set('QUERY', JSON.stringify(request.query));\n  res.redirect('/movies');\n});\n\napp.get('/movies', (request, res) => {\n  res.set('QUERY', JSON.stringify(request.query));\n  res.redirect('/movies/all');\n});\n\napp.get('/movies/all', (request, res) => {\n  res.set('QUERY', JSON.stringify(request.query));\n  res.redirect('/movies/all/0');\n});\n\napp.get('/movies/all/0', (request, res) => {\n  res.set('QUERY', JSON.stringify(request.query));\n  res.status(200).send('first movie page');\n});\n\napp.get('/movies/random', (request, res) => {\n  res.redirect('/movie/4');\n});\n\napp.get('/movie/4', (request, res) => {\n  setTimeout(() => {\n    res.send('not-so-random movie');\n  }, 1000);\n});\n\napp.get('/links', (request, res) => {\n  res.header(\n    'Link',\n    '<https://api.github.com/repos/visionmedia/mocha/issues?page=2>; rel=\"next\"'\n  );\n  res.end();\n});\n\napp.get('/xml', (request, res) => {\n  res.type('xml');\n  res.status(200).send('<some><xml></xml></some>');\n});\n\napp.get('/custom', (request, res) => {\n  res.type('application/x-custom');\n  res.status(200).send('custom stuff');\n});\n\napp.put('/user/:id', (request, res) => {\n  res.send('updated');\n});\n\napp.put('/user/:id/body', (request, res) => {\n  res.send(`received ${request.body.user}`);\n});\n\napp.patch('/user/:id', (request, res) => {\n  res.send('updated');\n});\n\napp.post('/user/:id/pet', (request, res) => {\n  res.send(`added pet \"${request.body.pet}\"`);\n});\n\napp.post('/user', (request, res) => {\n  res.send('created');\n});\n\napp.delete('/user/:id', (request, res) => {\n  res.send('deleted');\n});\n\napp.post('/todo/item', (request, res) => {\n  let buf = '';\n  request.on('data', (chunk) => {\n    buf += chunk;\n  });\n  request.on('end', () => {\n    res.send(`added \"${buf}\"`);\n  });\n});\n\napp.get('/delay/const', (request, res) => {\n  res.redirect('/delay/3000');\n});\n\napp.get('/delay/zip', (request, res) => {\n  res.writeHead(200, {\n    'Content-Type': 'text/plain',\n    'Content-Encoding': 'gzip'\n  });\n  setTimeout(() => {\n    res.end();\n  }, 10_000);\n});\n\napp.get('/delay/json', (request, res) => {\n  res.writeHead(200, { 'Content-Type': 'application/json' });\n  setTimeout(() => {\n    res.end();\n  }, 10_000);\n});\n\nlet slowBodyCallback;\napp.get('/delay/slowbody', (request, res) => {\n  res.writeHead(200, { 'Content-Type': 'application/octet-stream' });\n\n  // Send lots of garbage data to overflow all buffers along the way,\n  // so that the browser gets some data before the request is done\n  const initialDataSent = new Promise((resolve) => {\n    res.write(Buffer.alloc(4000), () => {\n      res.write(Buffer.alloc(16_000));\n      resolve();\n    });\n  });\n\n  // Make sure sending of request body takes over 1s,\n  // so that the test can't pass by accident.\n  const minimumTime = new Promise((resolve) => {\n    setTimeout(resolve, 1001);\n  });\n\n  new Promise((resolve) => {\n    // Waiting full 10 seconds for the test would be too annoying,\n    // so the remote callback is a hack to push the test forward\n    slowBodyCallback = resolve;\n    setTimeout(resolve, 10_000);\n  })\n    .then(() => Promise.all([initialDataSent, minimumTime]))\n    .then(() => {\n      res.end('bye');\n    });\n});\n\napp.get('/delay/slowbody/finish', (request, res) => {\n  if (slowBodyCallback) slowBodyCallback();\n  res.sendStatus(204);\n});\n\napp.get('/delay/:ms', (request, res) => {\n  const ms = Math.trunc(request.params.ms);\n  setTimeout(() => {\n    res.sendStatus(200);\n  }, ms);\n});\n\napp.get('/querystring', (request, res) => {\n  res.send(request.query);\n});\n\napp.get('/querystring-in-header', (request, res) => {\n  res.set('query', JSON.stringify(request.query));\n  res.send();\n});\n\napp.all('/echo-header/:field', (request, res) => {\n  res.send(request.headers[request.params.field]);\n});\n\napp.get('/echo-headers', (request, res) => {\n  res.json(request.headers);\n});\n\napp.post('/pet', (request, res) => {\n  res.send(`added ${request.body.name} the ${request.body.species}`);\n});\n\napp.get('/pets', (request, res) => {\n  res.send(['tobi', 'loki', 'jane']);\n});\n\napp.get('/json-seq', (request, res) => {\n  res\n    .set('content-type', 'application/json-seq')\n    .send('\\u001E{\"id\":1}\\n\\u001E{\"id\":2}\\n');\n});\n\napp.get('/invalid-json', (request, res) => {\n  res.set('content-type', 'application/json');\n  // sample invalid json taken from https://github.com/swagger-api/swagger-ui/issues/1354\n  res.send(\n    \")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}\"\n  );\n});\n\napp.get('/invalid-json-forbidden', (request, res) => {\n  res.set('content-type', 'application/json');\n  res.status(403).send('Forbidden');\n});\n\napp.get('/text', (request, res) => {\n  res.send('just some text');\n});\n\napp.get('/basic-auth', basicAuth('tobi', 'learnboost'), (request, res) => {\n  res.end('you win!');\n});\n\napp.get('/basic-auth/again', basicAuth('tobi', ''), (request, res) => {\n  res.end('you win again!');\n});\n\napp.post('/auth', basicAuth('foo', 'bar'), (request, res) => {\n  const auth = request.headers.authorization;\n  const parts = auth.split(' ');\n  const credentials = Buffer.from(parts[1], 'base64').toString().split(':');\n  const user = credentials[0];\n  const pass = credentials[1];\n\n  res.send({ user, pass });\n});\n\napp.get('/error', (request, res) => {\n  res.status(500).send('boom');\n});\n\napp.get('/unauthorized', (request, res) => {\n  res.sendStatus(401);\n});\n\napp.get('/bad-request', (request, res) => {\n  res.sendStatus(400);\n});\n\napp.get('/not-acceptable', (request, res) => {\n  res.sendStatus(406);\n});\n\napp.get('/no-content', (request, res) => {\n  res.sendStatus(204);\n});\n\napp.delete('/no-content', (request, res) => {\n  res.set('content-type', 'application/json');\n  res.sendStatus(204);\n});\n\napp.post('/created', (request, res) => {\n  res.status(201).send('created');\n});\n\napp.post('/unprocessable-entity', (request, res) => {\n  res.status(422).send('unprocessable entity');\n});\n\napp.get('/arraybuffer', (request, res) => {\n  const content = new ArrayBuffer(1000);\n  res.set('Content-Type', 'application/vnd.superagent');\n  res.send(content);\n});\n\napp.get('/arraybuffer-unauthorized', (request, res) => {\n  res.set('Content-Type', 'application/json');\n  res\n    .status(401)\n    .send('{\"message\":\"Authorization has been denied for this request.\"}');\n});\n\napp.post('/empty-body', bodyParser.text(), (request, res) => {\n  if (\n    typeof request.body === 'object' &&\n    Object.keys(request.body).length === 0\n  ) {\n    res.sendStatus(204);\n  } else {\n    res.sendStatus(400);\n  }\n});\n\napp.get('/collection-json', (request, res) => {\n  res.set('content-type', 'application/vnd.collection+json');\n  res.send({ name: 'chewbacca' });\n});\n\napp.get('/invalid-json', (request, res) => {\n  res.set('content-type', 'application/json');\n  // sample invalid json taken from https://github.com/swagger-api/swagger-ui/issues/1354\n  res.send(\n    \")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}\"\n  );\n});\n\napp.options('/options/echo/body', bodyParser.json(), (request, res) => {\n  res.send(request.body);\n});\n\napp.get('/cookie-redirect', (request, res) => {\n  res.set('Set-Cookie', 'replaced=yes');\n  res.append('Set-Cookie', 'from-redir=1', true);\n  res.redirect(303, '/show-cookies');\n});\n\napp.get('/set-cookie', (request, res) => {\n  res.cookie('replaced', 'no');\n  res.cookie('persist', '123');\n  res.send('ok');\n});\n\napp.get('/show-cookies', (request, res) => {\n  res.set('content-type', 'text/plain');\n  res.send(request.headers.cookie);\n});\n\napp.put('/redirect-303', (request, res) => {\n  res.redirect(303, '/reply-method');\n});\n\napp.put('/redirect-307', (request, res) => {\n  res.redirect(307, '/reply-method');\n});\n\napp.put('/redirect-308', (request, res) => {\n  res.redirect(308, '/reply-method');\n});\n\napp.all('/reply-method', (request, res) => {\n  res.send(`method=${request.method.toLowerCase()}`);\n});\n\napp.get('/tobi', (request, res) => {\n  res.send('tobi');\n});\n\napp.get('/relative', (request, res) => {\n  res.redirect('tobi');\n});\n\napp.get('/relative/sub', (request, res) => {\n  res.redirect('../tobi');\n});\n\napp.get('/header', (request, res) => {\n  res.redirect('/header/2');\n});\n\napp.post('/header', (request, res) => {\n  res.redirect('/header/2');\n});\n\napp.get('/header/2', (request, res) => {\n  res.send(request.headers);\n});\n\napp.get('/bad-redirect', (request, res) => {\n  res.status(307).end();\n});\n\napp.all('/ua', (request, res) => {\n  const { headers } = request;\n  if (process.env.HTTP2_TEST) {\n    for (const name of Object.keys(headers)) {\n      if (isPseudoHeader(name)) {\n        delete headers[name];\n      }\n    }\n  }\n\n  res.writeHead(200, headers);\n  request.pipe(res);\n});\n\napp.get('/manny', (request, res) => {\n  res.status(200).json({ name: 'manny' });\n});\n\nfunction serveImageWithType(res, type) {\n  const img = fs.readFileSync(\n    path.join(__dirname, '../node/fixtures/test.png')\n  );\n  res.writeHead(200, { 'Content-Type': type });\n  res.end(img, 'binary');\n}\n\napp.get('/image', (request, res) => {\n  serveImageWithType(res, 'image/png');\n});\napp.get('/image-as-octets', (request, res) => {\n  serveImageWithType(res, 'application/octet-stream');\n});\n\napp.get('/binary-data', (request, res) => {\n  const binData = fs.readFileSync(\n    path.join(__dirname, '../node/fixtures/test.aac')\n  );\n  res.writeHead(200, { 'Content-type': 'audio/aac' });\n  res.end(binData, 'binary');\n});\n\napp.get('/chunked-json', (request, res) => {\n  res.set('content-type', 'application/json');\n  res.set('Transfer-Encoding', 'chunked');\n\n  let chunk = 0;\n  const interval = setInterval(() => {\n    chunk++;\n    if (chunk === 1) res.write(`{ \"name_${chunk}\": \"`);\n    if (chunk > 1) res.write(`value_${chunk}\", \"name_${chunk}\": \"`);\n    if (chunk === 10) {\n      clearInterval(interval);\n      res.write(`value_${chunk}\"}`);\n      res.end();\n    }\n  }, 10);\n});\n\napp.get('/if-mod', (request, res) => {\n  if (request.header('if-modified-since')) {\n    res.status(304).end();\n  } else {\n    res.send(`${Date.now()}`);\n  }\n});\n\nconst called = {};\napp.get('/error/ok/:id', (request, res) => {\n  if (request.query.qs !== 'present') {\n    return res.status(400).end('query string lost');\n  }\n\n  const { id } = request.params;\n  if (!called[id]) {\n    called[id] = true;\n    res.status(500).send('boom');\n  } else {\n    res.send(request.headers);\n    delete called[id];\n  }\n});\n\napp.get('/delay/:ms/ok/:id', (request, res) => {\n  const { id } = request.params;\n  if (!called[id]) {\n    called[id] = true;\n    const ms = Math.trunc(request.params.ms);\n    setTimeout(() => {\n      res.sendStatus(200);\n    }, ms);\n  } else {\n    res.send(`ok = ${request.url}`);\n    delete called[id];\n  }\n});\n\napp.get('/error/redirect/:id', (request, res) => {\n  const { id } = request.params;\n  if (!called[id]) {\n    called[id] = true;\n    res.status(500).send('boom');\n  } else {\n    res.redirect('/movies');\n    delete called[id];\n  }\n});\n\napp.get('/error/redirect-error:id', (request, res) => {\n  const { id } = request.params;\n  if (!called[id]) {\n    called[id] = true;\n    res.status(500).send('boom');\n  } else {\n    res.redirect('/error');\n    delete called[id];\n  }\n});\n\nconst server = http.createServer(app);\nserver.listen(process.env.ZUUL_PORT);\n"
  },
  {
    "path": "test/support/setup.js",
    "content": "require('should');\nrequire('should-http');\n\nconst getPort = require('get-port');\n\nlet NODE;\nlet uri;\n\nasync function getSetup() {\n  if (NODE && uri) {\n    return { NODE, uri };\n  }\n\n  NODE = true;\n  if (typeof window !== 'undefined') {\n    NODE = false;\n    uri = `//${window.location.host}`;\n  } else {\n    try {\n      const port = await getPort();\n\n      // check that another call to the function hasn't set the uri already\n      if (!uri) {\n        process.env.ZUUL_PORT = port;\n        uri = `http://localhost:${process.env.ZUUL_PORT}`;\n        require('./server');\n      }\n    } catch (err) {\n      console.error(err);\n    }\n  }\n\n  return { NODE, uri };\n}\n\nmodule.exports = getSetup;\n"
  },
  {
    "path": "test/timeout.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\ndescribe('.timeout(ms)', function () {\n  let setup;\n  let base;\n\n  before(async () => {\n    setup = await getSetup();\n    base = setup.uri;\n  });\n\n  this.timeout(15_000);\n\n  describe('when timeout is exceeded', () => {\n    it('should error', (done) => {\n      request\n        .get(`${base}/delay/500`)\n        .timeout(150)\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          done();\n        });\n    });\n\n    it('should error in promise interface ', (done) => {\n      request\n        .get(`${base}/delay/500`)\n        .timeout(150)\n        .catch((err) => {\n          assert(err, 'expected an error');\n          assert.equal(\n            'number',\n            typeof err.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', err.code, 'expected abort error code');\n          done();\n        });\n    });\n\n    it('should handle gzip timeout', (done) => {\n      request\n        .get(`${base}/delay/zip`)\n        .timeout(150)\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          done();\n        });\n    });\n\n    it('should handle buffer timeout', (done) => {\n      request\n        .get(`${base}/delay/json`)\n        .buffer(true)\n        .timeout(150)\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          done();\n        });\n    });\n\n    it('should error on deadline', (done) => {\n      request\n        .get(`${base}/delay/500`)\n        .timeout({ deadline: 150 })\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          done();\n        });\n    });\n\n    it('should support setting individual options', (done) => {\n      request\n        .get(`${base}/delay/500`)\n        .timeout({ deadline: 10 })\n        .timeout({ response: 99_999 })\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          assert.equal('ETIME', error.errno);\n          done();\n        });\n    });\n\n    it('should error on response', (done) => {\n      request\n        .get(`${base}/delay/500`)\n        .timeout({ response: 150 })\n        .end((error, res) => {\n          assert(error, 'expected an error');\n          assert.equal(\n            'number',\n            typeof error.timeout,\n            'expected an error with .timeout'\n          );\n          assert.equal('ECONNABORTED', error.code, 'expected abort error code');\n          assert.equal('ETIMEDOUT', error.errno);\n          done();\n        });\n    });\n\n    it('should accept slow body with fast response', (done) => {\n      request\n        .get(`${base}/delay/slowbody`)\n        .timeout({ response: 1000 })\n        .on('progress', () => {\n          // This only makes the test faster without relying on arbitrary timeouts\n          request.get(`${base}/delay/slowbody/finish`).end();\n        })\n        .end(done);\n    });\n  });\n});\n"
  },
  {
    "path": "test/use.js",
    "content": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/client');\n\ndescribe('request', function () {\n  let setup;\n  let uri;\n\n  before(async function () {\n    setup = await getSetup();\n    uri = setup.uri;\n  });\n\n  this.timeout(20_000);\n  describe('use', () => {\n    it('should use plugin success', (done) => {\n      const now = `${Date.now()}`;\n      function uuid(request_) {\n        request_.set('X-UUID', now);\n        return request_;\n      }\n\n      function prefix(request_) {\n        request_.url = uri + request_.url;\n        return request_;\n      }\n\n      request\n        .get('/echo')\n        .use(uuid)\n        .use(prefix)\n        .end((error, res) => {\n          assert.strictEqual(res.statusCode, 200);\n          assert.equal(res.get('X-UUID'), now);\n          done();\n        });\n    });\n  });\n});\n\ndescribe('subclass', () => {\n  let OriginalRequest;\n  beforeEach(() => {\n    OriginalRequest = request.Request;\n  });\n  afterEach(() => {\n    request.Request = OriginalRequest;\n  });\n\n  it('should be an instance of Request', () => {\n    const request_ = request.get('/');\n    assert(request_ instanceof request.Request);\n  });\n\n  it('should use patched subclass', () => {\n    assert(OriginalRequest);\n\n    let constructorCalled;\n    let sendCalled;\n    function NewRequest(...args) {\n      constructorCalled = true;\n      OriginalRequest.apply(this, args);\n    }\n\n    NewRequest.prototype = Object.create(OriginalRequest.prototype);\n    NewRequest.prototype.send = function () {\n      sendCalled = true;\n      return this;\n    };\n\n    request.Request = NewRequest;\n\n    const request_ = request.get('/').send();\n    assert(constructorCalled);\n    assert(sendCalled);\n    assert(request_ instanceof NewRequest);\n    assert(request_ instanceof OriginalRequest);\n  });\n\n  it('should use patched subclass in agent too', () => {\n    if (!request.agent) return; // Node-only\n\n    function NewRequest(...args) {\n      OriginalRequest.apply(this, args);\n    }\n\n    NewRequest.prototype = Object.create(OriginalRequest.prototype);\n    request.Request = NewRequest;\n\n    const request_ = request.agent().del('http://test.com/');\n    assert(request_ instanceof NewRequest);\n    assert(request_ instanceof OriginalRequest);\n  });\n});\n"
  }
]