Full Code of forwardemail/superagent for AI

master 3ef367619fbb cached
120 files
874.3 KB
272.8k tokens
75 symbols
1 requests
Download .txt
Showing preview only (913K chars total). Download the full file or copy to clipboard to get everything.
Repository: forwardemail/superagent
Branch: master
Commit: 3ef367619fbb
Files: 120
Total size: 874.3 KB

Directory structure:
gitextract_wy1qkpbs/

├── .browserslistrc
├── .commitlintrc.js
├── .dist.babelrc
├── .dist.eslintrc
├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .lib.babelrc
├── .lib.eslintrc
├── .lintstagedrc.js
├── .npmrc
├── .prettierrc.js
├── .remarkignore
├── .remarkrc.js
├── .test.babelrc
├── .travis.yml
├── .xo-config.js
├── .zuul.yml
├── CONTRIBUTING.md
├── HISTORY.md
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── ci/
│   └── remove-deps-4-old-node.js
├── docs/
│   ├── head.html
│   ├── index.md
│   ├── ko_KR/
│   │   ├── index.html
│   │   └── index.md
│   ├── style.css
│   ├── tail.html
│   ├── test.html
│   └── zh_CN/
│       ├── index.html
│       └── index.md
├── examples/
│   └── simple-get.js
├── index.html
├── package.json
├── src/
│   ├── agent-base.js
│   ├── client.js
│   ├── node/
│   │   ├── agent.js
│   │   ├── decompress.js
│   │   ├── http2wrapper.js
│   │   ├── index.js
│   │   ├── parsers/
│   │   │   ├── image.js
│   │   │   ├── index.js
│   │   │   ├── json.js
│   │   │   ├── text.js
│   │   │   └── urlencoded.js
│   │   ├── response.js
│   │   └── unzip.js
│   ├── request-base.js
│   ├── response-base.js
│   └── utils.js
└── test/
    ├── agent-base.js
    ├── basic.js
    ├── client/
    │   ├── request.js
    │   ├── serialize.js
    │   └── xdomain.js
    ├── content-type.js
    ├── form.js
    ├── json.js
    ├── node/
    │   ├── agency.js
    │   ├── basic-auth.js
    │   ├── basic.js
    │   ├── buffers.js
    │   ├── exports.js
    │   ├── fixtures/
    │   │   ├── ca.cert.pem
    │   │   ├── ca.key.pem
    │   │   ├── ca.srl
    │   │   ├── cert.csr
    │   │   ├── cert.pem
    │   │   ├── cert.pfx
    │   │   ├── key.pem
    │   │   ├── passcert.pfx
    │   │   ├── test.aac
    │   │   ├── user.html
    │   │   ├── user.json
    │   │   └── user.txt
    │   ├── flags.js
    │   ├── form.js
    │   ├── http2.js
    │   ├── https.js
    │   ├── image.js
    │   ├── incoming-multipart.js
    │   ├── inflate.js
    │   ├── lookup.js
    │   ├── multipart.js
    │   ├── network-error.js
    │   ├── not-modified.js
    │   ├── parsers.js
    │   ├── pipe-callback.js
    │   ├── pipe-redirect.js
    │   ├── pipe.js
    │   ├── query.js
    │   ├── redirects-other-host.js
    │   ├── redirects.js
    │   ├── response-readable-stream.js
    │   ├── serialize.js
    │   ├── set-host.js
    │   ├── toError.js
    │   ├── unix-sockets.js
    │   ├── user-agent.js
    │   └── utils.js
    ├── redirects.js
    ├── request.js
    ├── retry.js
    ├── support/
    │   ├── blank.js
    │   ├── client.js
    │   ├── express/
    │   │   ├── index.js
    │   │   ├── requestDecorator.js
    │   │   ├── responseDecorator.js
    │   │   └── utils.js
    │   ├── server.js
    │   └── setup.js
    ├── timeout.js
    └── use.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .browserslistrc
================================================
defaults, not ie 11


================================================
FILE: .commitlintrc.js
================================================
module.exports = {
  extends: ['@commitlint/config-conventional']
};


================================================
FILE: .dist.babelrc
================================================
{
  "presets": [
    ["@babel/env", {
      "targets": {
        "browsers": [ "defaults, not ie 11" ]
      }
    }]
  ],
  "sourceType": "script",
  "sourceMaps": "inline",
  "comments": false
}


================================================
FILE: .dist.eslintrc
================================================
{
  "extends": ["eslint:recommended", "plugin:compat/recommended"],
  "env": {
    "node": false,
    "browser": true,
    "amd": true,
    "es6": true
  },
  "plugins": ["compat"],
  "rules": {
    "node/no-unsupported-features/es-builtins": "off",
    "compat/compat": "error",
    "no-console": "off",
    "no-empty": "off",
    "no-extra-semi": "off",
    "no-func-assign": "off",
    "no-undef": "off",
    "no-unused-vars": "off",
    "no-useless-escape": "off",
    "no-obj-calls": "off",
    "no-cond-assign": "off",
    "no-redeclare": "off",
    "node/no-exports-assign": "off",
    "no-unsafe-finally": "off",
    "complexity": ["error", 10000],
    "max-statements": "off",
    "no-constant-condition": "off",
    "no-control-regex": "off",
    "no-fallthrough": "off",
    "operator-linebreak": "off",
    "node/no-missing-require": "warn"
  },
  "globals": {
    "regeneratorRuntime": "writable"
  },
  "settings": {
    "polyfills": [
      "WeakRef",
      "BigInt"
    ]
  }
}


================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true


================================================
FILE: .eslintrc
================================================
{
  "extends": [
    "eslint:recommended",
    "plugin:node/recommended"
  ],
  "env": {
    "node": true,
    "browser": true,
    "es6": true
  },
  "parserOptions": {
    "ecmaVersion": 2021
  },
  "overrides": [
    {
      "files": "test/**/*.js",
      "env": {
        "mocha": true
      },
      "rules": {
        "no-prototype-builtins": "off",
        "node/no-deprecated-api": "warn",
        "node/no-extraneous-require": "warn",
        "no-unused-vars": "warn",
        "node/no-missing-require": "warn"
      }
    }
  ],
  "rules": {
    "node/no-unsupported-features/node-builtins": "off",
    "node/no-unsupported-features/es-syntax": "off",
    "node/no-exports-assign": "off",
    "no-unused-vars": "warn"
  },
  "globals": {
  }
}


================================================
FILE: .gitattributes
================================================
* text=auto


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on: [push, pull_request]

env:
  SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
  SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}

permissions:
  contents: read #  to fetch code (actions/checkout)

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
       include:
        - node-version: 18.x
        - node-version: 20.x
        - node-version: 22.x
        - node-version: 24.x
    steps:
      - uses: actions/checkout@v4

      - name: Install Node - ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Test On Node ${{ matrix.node-version }}
        env:
          BROWSER: ${{ matrix.test-on-brower }}
          HTTP2_TEST_DISABLED: ${{ matrix.http2-test-disabled }}
          OLD_NODE_TEST: ${{ matrix.test-on-old-node }}
        run: |
          if [ "$OLD_NODE_TEST" = "1" ]; then
            make test
          else
            npm run lint
            make test
          fi
      - name: Coverage On Node ${{ matrix.node-version }}
        run: npm run coverage
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4


================================================
FILE: .gitignore
================================================
.vscode
build
lib-cov
coverage.html
.DS_Store
node_modules
*.sock
test.js
components
test/node/fixtures/tmp.json
.idea
superagent.js
*.log
coverage
.nyc_output
lib
dist
*.swp
yarn.lock


================================================
FILE: .husky/commit-msg
================================================
npx commitlint --edit $1


================================================
FILE: .husky/pre-commit
================================================
npx lint-staged


================================================
FILE: .lib.babelrc
================================================
{
  "presets": [
    ["@babel/env", {
      "targets": {
        "node": "14.18.0",
        "browsers": [ "defaults, not ie 11" ]
      }
    }]
  ],
  "sourceMaps": "inline"
}


================================================
FILE: .lib.eslintrc
================================================
{
  "extends": ["eslint:recommended", "plugin:node/recommended"],
  "env": {
    "browser": true
  },
  "rules": {
    "node/no-unsupported-features/es-builtins": ["error", {
      "version": ">=6.4.0",
      "ignores": [
      ]
    }],
    "node/no-deprecated-api": "off",
    "no-console": "off",
    "no-unused-vars": "off",
    "no-empty": "off",
    "no-func-assign": "off",
    "no-global-assign": ["error", {"exceptions": ["exports"]}],
    "no-fallthrough": "off",
    "no-constant-condition": "off",
    "node/no-exports-assign": "off",
    "no-unsafe-finally": "off"
  },
  "overrides": [
    {
      "files": [ "lib/client.js" ],
      "globals": {
      }
    },
    {
      "files": [ "lib/node/http2wrapper.js" ],
      "rules": {
        "node/no-unsupported-features/es-builtins": "off",
        "node/no-unsupported-features/node-builtins": "off"
      }
    }
  ]
}


================================================
FILE: .lintstagedrc.js
================================================
module.exports = {
  "*.md": filenames => filenames.map(filename => `remark ${filename} -qfo`),
  '*.js': 'xo --fix'
};


================================================
FILE: .npmrc
================================================
package-lock=true


================================================
FILE: .prettierrc.js
================================================
module.exports = {
  singleQuote: true,
  bracketSpacing: true,
  trailingComma: 'none'
};


================================================
FILE: .remarkignore
================================================
CONTRIBUTING.md
HISTORY.md
docs


================================================
FILE: .remarkrc.js
================================================
module.exports = {
  plugins: ['preset-github']
};


================================================
FILE: .test.babelrc
================================================
{
  "presets": [
    ["@babel/env", {
      "targets": {
        "node": "14.18.0",
        "browsers": [ "defaults, not ie 11" ]
      }
    }]
  ],
  "plugins": [
    ["@babel/transform-runtime"]
  ],
  "parserOpts": {
    "allowReturnOutsideFunction": true
  },
  "sourceMaps": "inline"
}


================================================
FILE: .travis.yml
================================================
sudo: false
language: node_js
node_js:
  - '18'
  - '16'
  - '14'
after_success: npm run coverage

env:
  global:
    - SAUCE_USERNAME='shtylman-superagent'
    - SAUCE_ACCESS_KEY='39a45464-cb1d-4b8d-aa1f-83c7c04fa673'


================================================
FILE: .xo-config.js
================================================
module.exports = {
	prettier: true,
	space: true,
	nodeVersion: false,
	extends: [
		'xo-lass',
	],
	envs: [
		'node',
		'browser',
	],
	overrides: [
		{
			files: 'test/**/*.js',
			envs: [
				'mocha',
			],
			rules: {
				'block-scoped-var': 'warn',
				complexity: 'warn',
				'default-case': 'warn',
				eqeqeq: 'warn',
				'func-name-matching': 'warn',
				'func-names': 'warn',
				'guard-for-in': 'warn',
				'handle-callback-err': 'warn',
				'import/no-extraneous-dependencies': 'warn',
				'import/no-unassigned-import': 'warn',
				'import/order': 'warn',
				'max-nested-callbacks': 'warn',
				'new-cap': 'warn',
				'no-eq-null': 'warn',
				'no-extend-native': 'warn',
				'no-implicit-coercion': 'warn',
				'no-multi-assign': 'warn',
				'no-negated-condition': 'off',
				'no-prototype-builtins': 'warn',
				'no-redeclare': 'warn',
				'no-undef': 'warn',
				'no-unused-expressions': 'warn',
				'no-unused-vars': 'warn',
				'no-use-extend-native/no-use-extend-native': 'warn',
				'no-useless-escape': 'warn',
				'no-var': 'warn',
				'no-void': 'warn',
				'n/no-deprecated-api': 'warn',
				'prefer-rest-params': 'warn',
				'prefer-spread': 'warn',
				'unicorn/filename-case': 'warn',
				'valid-jsdoc': 'warn',
				'n/no-path-concat': 'warn',
				'unicorn/no-empty-file': 'warn',
				'unicorn/expiring-todo-comments': 'off',
				'n/prefer-global/buffer': 'off',
				'n/prefer-global/process': 'off',
			},
		},
	],
	rules: {
		'unicorn/prevent-abbreviations': [
			'warn',
			{
				replacements: {
					res: false,
					args: false,
					fn: false,
					err: false,
					e: false,
					i: false,
				},
			},
		],
		'no-bitwise': 'warn',
		'n/prefer-global/buffer': 'off',
		'n/prefer-global/process': 'off',
		'unicorn/no-new-array': 'warn',
		'unicorn/no-this-assignment': 'warn',
		'unicorn/prefer-spread': 'warn',
		'unicorn/catch-error-name': 'warn',
		'unicorn/prefer-code-point': 'warn',
		'n/no-unsupported-features': [
			'error',
			{
				version: 8,
				ignores: [
					'syntax',
				],
			},
		],
    'unicorn/prefer-optional-catch-binding': 'off',
    'no-unused-vars': 'off',
    'unicorn/expiring-todo-comments': 'off'
	},
	globals: [],
};


================================================
FILE: .zuul.yml
================================================
ui: mocha-bdd
server: ./test/support/server.js
tunnel_host: http://focusaurus.com
browsers:
  - name: chrome
    version: latest
  - name: firefox
    version: latest
  - name: safari
    version: latest
  - name: ie
    version: 9..latest
browserify:
  - transform:
      name: babelify
      configFile: './.dist.babelrc'


================================================
FILE: CONTRIBUTING.md
================================================
When submitting a PR, your chance of acceptance increases if you do the following:

* Code style is consistent with existing in the file.
* Tests are passing (client and server).
* You add a test for the failing issue you are fixing.
* Code changes are focused on the area of discussion.
* Do not rebuild the distribution files or increment version numbers.


================================================
FILE: HISTORY.md
================================================
# This HISTORY log is deprecated

Please see [GitHub releases page](https://github.com/ladjs/superagent/releases) for the current changelog.

# 4.1.0 (2018-12-26)

 * `.connect()` IP/DNS override option (Kornel)
 * `.trustLocalhost()` option for allowing broken HTTPS on `localhost`
 * `.abort()` used with promises rejects the promise.

# 4.0.0 (2018-11-17)

## Breaking changes

* 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.
* We now use ES6 in the browser code, too.
  * If you're using Browserify or Webpack to package code for Internet Explorer, you will also have to use Babel.
  * The pre-built node_modules/superagent.js is still ES5-compatible.
* `.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.
* 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`.
* Invalid uses of `.pipe()` throw.


## Minor changes

* Throw if `req.abort().end()` is called
* Throw if using unsupported mix of send and field
* Reject `.end()` promise on all error events (Kornel Lesiński)
* Set `https.servername` from the `Host` header (Kornel Lesiński)
* Leave backticks unencoded in query strings where possible (Ethan Resnick)
* Update node-mime to 2.x (Alexey Kucherenko)
* Allow default buffer settings based on response-type (shrey)
* `response.buffered` is more accurate.

# 3.8.3 (2018-04-29)

* Add flags for 201 & 422 responses (Nikhil Fadnis)
* Emit progress event while uploading Node `Buffer` via send method (Sergey Akhalkov)
* Fixed setting correct cookies for redirects (Damien Clark)
* Replace .catch with ['catch'] for IE9 Support (Miguel Stevens)

# 3.8.2 (2017-12-09)

* Fixed handling of exceptions thrown from callbacks
* Stricter matching of `+json` MIME types.

# 3.8.1 (2017-11-08)

* Clear authorization header on cross-domain redirect

# 3.8.0

* Added support for "globally" defined headers and event handlers via `superagent.agent()`. It now remembers default settings for all its requests.
* Added optional callback to `.retry()` (Alexander Murphy)
* Unified auth args handling in node/browser (Edmundo Alvarez)
* Fixed error handling in zlib pipes (Kornel)
* Documented that 3xx status codes are errors (Mickey Reiss)

# 3.7.0 (2017-10-17)

* Limit maximum response size. Prevents zip bombs (Kornel)
* Catch and pass along errors in `.ok()` callback (Jeremy Ruppel)
* Fixed parsing of XHR headers without a newline (nsf)

# 3.6.2 (2017-10-02)

* Upgrade MIME type dependency to a newer, secure version
* Recognize PDF MIME as binary
* Fix for error in subsequent require() calls (Steven de Salas)

# 3.6.0 (2017-08-20)

* Support disabling TCP_NODELAY option ([#1240](https://github.com/ladjs/superagent/issues/1240)) (xiamengyu)
* Send payload in query string for GET and HEAD shorthand API (Peter Lyons)
* Support passphrase with pfx certificate (Paul Westerdale (ABRS Limited))
* Documentation improvements (Peter Lyons)
* Fixed duplicated query string params ([#1200](https://github.com/ladjs/superagent/issues/1200)) (Kornel)

# 3.5.1 (2017-03-18)

* Allow crossDomain errors to be retried ([#1194](https://github.com/ladjs/superagent/issues/1194)) (Michael Olson)
* Read responseType property from the correct object (Julien Dupouy)
* Check for ownProperty before adding header (Lucas Vieira)

# 3.5.0 (2017-02-23)

* Add errno to distinguish between request timeout and body download timeout ([#1184](https://github.com/ladjs/superagent/issues/1184)) (Kornel Lesiński)
* Warn about bogus timeout options ([#1185](https://github.com/ladjs/superagent/issues/1185)) (Kornel Lesiński)

# 3.4.4 (2017-02-17)

* Treat videos like images (Kornel Lesiński)
* Avoid renaming module (Kornel Lesiński)

# 3.4.3 (2017-02-14)

* Fixed being able to define own parsers when their mime type starts with `text/` (Damien Clark)
* `withCredentials(false)` (Andy Woods)
* Use `formData.on` instead of `.once` (Kornel Lesiński)
* Ignore `attach("file",null)` (Kornel Lesiński)

# 3.4.1 (2017-01-29)

* Allow `retry()` and `retry(0)` (Alexander Pope)
* Allow optional body/data in DELETE requests (Alpha Shuro)
* Fixed query string on retried requests (Kornel Lesiński)

# 3.4.0 (2017-01-25)

* New `.retry(n)` method and `err.retries` (Alexander Pope)
* Docs for HTTPS request (Jun Wan Goh)

# 3.3.1 (2016-12-17)

* Fixed "double callback bug" warning on timeouts of gzipped responses

# 3.3.0 (2016-12-14)

* Added `.ok(callback)` that allows customizing which responses are errors (Kornel Lesiński)
* Added `.responseType()` to Node version (Kornel Lesiński)
* Added `.parse()` to browser version (jakepearson)
* Fixed parse error when using `responseType('blob')` (Kornel Lesiński)

# 3.2.0 (2016-12-11)

* Added `.timeout({response:ms})`, which allows limiting maximum response time independently from total download time (Kornel Lesiński)
* Added warnings when `.end()` is called more than once (Kornel Lesiński)
* Added `response.links` to browser version (Lukas Eipert)
* `btoa` is no longer required in IE9 (Kornel Lesiński)
* Fixed `.sortQuery()` on URLs without query strings (Kornel Lesiński)
* Refactored common response code into `ResponseBase` (Lukas Eipert)

# 3.1.0 (2016-11-28)

* Added `.sortQuery()` (vicanso)
* Added support for arrays and bools in `.field()` (Kornel Lesiński)
* Made `superagent.Request` subclassable without need to patch all static methods (Kornel Lesiński)

# 3.0.0 (2016-11-19)

* Dropped support for Node 0.x. Please upgrade to at least Node 4.
* Dropped support for componentjs (Damien Caselli)
* Removed deprecated `.part()`/`superagent.Part` APIs.
* Removed unreliable `.body` property on internal response object used by unbuffered parsers.
  Note: the normal `response.body` is unaffected.
* Multiple `.send()` calls mixing `Buffer`/`Blob` and JSON data are not possible and will now throw instead of messing up the data.
* Improved `.send()` data object type check (Fernando Mendes)
* Added common prototype for Node and browser versions (Andreas Helmberger)
* Added `http+unix:` schema to support Unix sockets (Yuki KAN)
* Added full `attach` options parameter in the Node version (Lapo Luchini)
* Added `pfx` TLS option with new `pfx()` method. (Reid Burke)
* Internally changed `.on` to `.once` to prevent possible memory leaks (Matt Blair)
* Made all errors reported as an event (Kornel Lesiński)

# 2.3.0 (2016-09-20)

* Enabled `.field()` to handle objects (Affan Shahid)
* Added authentication with client certificates (terusus)
* Added `.catch()` for more Promise-like interface (Maxim Samoilov, Kornel Lesiński)
* Silenced errors from incomplete gzip streams for compatibility with web browsers (Kornel Lesiński)
* Fixed `event.direction` in uploads (Kornel Lesiński)
* Fixed returned value of overwritten response object's `on()` method (Juan Dopazo)

# 2.2.0 (2016-08-13)

* Added `timedout` property to node Request instance (Alexander Pope)
* Unified `null` querystring values in node and browser environments. (George Chung)

# 2.1.0 (2016-06-14)

* Refactored async parsers. Now the `end` callback waits for async parsers to finish (Kornel Lesiński)
* Errors thrown in `.end()` callback don't cause the callback to be called twice (Kornel Lesiński)
* Added `headers` to `toJSON()` (Tao)

# 2.0.0 (2016-05-29)


## Breaking changes

Breaking changes are in rarely used functionality, so we hope upgrade will be smooth for most users.

* Browser: The `.parse()` method has been renamed to `.serialize()` for consistency with NodeJS version.
* Browser: Query string keys without a value used to be parsed as `'undefined'`, now their value is `''` (empty string) (shura, Kornel Lesiński).
* 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)
* `.then()` returns a real `Promise`. Note that use of superagent with promises now requires a global `Promise` object.
  If you target Internet Explorer or Node 0.10, you'll need `require('es6-promise').polyfill()` or similar.
* Upgraded all dependencies (Peter Lyons)
* Renamed properties documented as `@api private` to have `_prefixed` names (Kornel Lesiński)


## Probably not breaking changes:

* Extracted common functions to request-base (Peter Lyons)
* Fixed race condition in pipe tests (Peter Lyons)
* Handle `FormData` error events (scriptype)
* Fixed wrong jsdoc of Request#attach (George Chung)
* Updated and improved tests (Peter Lyons)
* `request.head()` supports `.redirects(5)` call (Kornel Lesiński)
* `response` event is also emitted when using `.pipe()`

# 1.8.2 (2016-03-20)

* Fixed handling of HTTP status 204 with content-encoding: gzip (Andrew Shelton)
* Handling of FormData error events (scriptype)
* Fixed parsing of `vnd+json` MIME types (Kornel Lesiński)
* Aliased browser implementation of `.parse()` as `.serialize()` for forward compatibility

# 1.8.1 (2016-03-14)

* Fixed form-data incompatibility with IE9

# 1.8.0 (2016-03-09)

* Extracted common code into request-base class (Peter Lyons)
  * It does not affect the public API, but please let us know if you notice any plugins/subclasses breaking!
* Added option `{type:'auto'}` to `auth` method, which enables browser-native auth types (Jungle, Askar Yusupov)
* Added `responseType()` to set XHR `responseType` (chris)
* Switched to form-data for browserify-compatible `FormData` (Peter Lyons)
* Added `statusCode` to error response when JSON response is malformed (mattdell)
* Prevented TCP port conflicts in all tests (Peter Lyons)
* Updated form-data dependency

# 1.7.2 (2016-01-26)

* Fix case-sensitivity of header fields introduced by [`a4ddd6a`](https://github.com/ladjs/superagent/commit/a4ddd6a). (Edward J. Jinotti)
* bump extend dependency, as former version did not contain any license information (Lukas Eipert)

# 1.7.1 (2016-01-21)

* Fixed a conflict with express when using npm 3.x (Glenn)
* Fixed redirects after a multipart/form-data POST request (cyclist2)

# 1.7.0 (2016-01-18)

* When attaching files, read default filename from the `File` object (JD Isaacks)
* Add `direction` property to `progress` events (Joseph Dykstra)
* Update component-emitter & formidable (Kornel Lesiński)
* Don't re-encode query string needlessly (Ruben Verborgh)
* ensure querystring is appended when doing `stream.pipe(request)` (Keith Grennan)
* change set header function, not call `this.request()` until call `this.end()` (vicanso)
* Add no-op `withCredentials` to Node API (markdalgleish)
* fix `delete` breaking on ie8 (kenjiokabe)
* Don't let request error override responses (Clay Reimann)
* Increased number of tests shared between node and client (Kornel Lesiński)

# 1.6.0/1.6.1 (2015-12-09)

* avoid misleading CORS error message
* added 'progress' event on file/form upload in Node (Olivier Lalonde)
* return raw response if the response parsing fails (Rei Colina)
* parse content-types ending with `+json` as JSON (Eiryyy)
* fix to avoid throwing errors on aborted requests (gjurgens)
* retain cookies on redirect when hosts match (Tom Conroy)
* added Bower manifest (Johnny Freeman)
* upgrade to latest cookiejar (Andy Burke)

# 1.5.0 (2015-11-30)

* encode array values as `key=1&key=2&key=3` etc... (aalpern, Davis Kim)
* avoid the error which is omitted from 'socket hang up'
* faster JSON parsing, handling of zlib errors (jbellenger)
* fix IE11 sends 'undefined' string if data was undefined (Vadim Goncharov)
* alias `del()` method as `delete()` (Aaron Krause)
* revert Request#parse since it was actually Response#parse

# 1.4.0 (2015-09-14)

* add Request#parse method to client library
* add missing statusCode in client response
* don't apply JSON heuristics if a valid parser is found
* fix detection of root object for webworkers

# 1.3.0 (2015-08-05)

* fix incorrect content-length of data set to buffer
* serialize request data takes into account charsets
* add basic promise support via a `then` function

# 1.2.0 (2015-04-13)

* add progress events to downlodas
* make usable in webworkers
* add support for 308 redirects
* update node-form-data dependency
* update to work in react native
* update node-mime dependency

# 1.1.0 (2015-03-13)

* Fix responseType checks without xhr2 and ie9 tests (rase-)
* errors have .status and .response fields if applicable (defunctzombie)
* fix end callback called before saving cookies (rase-)

# 1.0.0 / 2015-03-08

* All non-200 responses are treated as errors now. (The callback is called with an error when the response has a status < 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).
* keep timeouts intact across redirects (hopkinsth)
* handle falsy json values (themaarten)
* fire response events in browser version (Schoonology)
* getXHR exported in client version (KidsKilla)
* remove arity check on `.end()` callbacks (defunctzombie)
* avoid setting content-type for host objects (rexxars)
* don't index array strings in querystring (travisjeffery)
* fix pipe() with redirects (cyrilis)
* add xhr2 file download (vstirbu)
* set default response type to text/plain if not specified (warrenseine)

# 0.21.0 / 2014-11-11

* Trim text before parsing json (gjohnson)
* Update tests to express 4 (gaastonsr)
* Prevent double callback when error is thrown (pgn-vole)
* Fix missing clearTimeout (nickdima)
* Update debug (TooTallNate)

# 0.20.0 / 2014-10-02

* Add toJSON() to request and response instances. (yields)
* Prevent HEAD requests from getting parsed. (gjohnson)
* Update debug. (TooTallNate)

# 0.19.1 / 2014-09-24

* Fix basic auth issue when password is falsey value. (gjohnson)

# 0.19.0 / 2014-09-24

* Add unset() to browser. (shesek)
* Prefer XHR over ActiveX. (omeid)
* Catch parse errors. (jacwright)
* Update qs dependency. (wercker)
* Add use() to node. (Financial-Times)
* Add response text to errors. (yields)
* Don't send empty cookie headers. (undoZen)
* Don't parse empty response bodies. (DveMac)
* Use hostname when setting cookie host. (prasunsultania)

# 0.18.2 / 2014-07-12

* Handle parser errors. (kof)
* Ensure not to use default parsers when there is a user defined one. (kof)

# 0.18.1 / 2014-07-05

* Upgrade cookiejar dependency (juanpin)
* Support image mime types (nebulade)
* Make .agent chainable (kof)
* Upgrade debug (TooTallNate)
* Fix docs (aheckmann)

# 0.18.0 / 2014-04-29

* Use "form-data" module for the multipart/form-data implementation. (TooTallNate)
* Add basic `field()` and `attach()` functions for HTML5 FormData. (TooTallNate)
* Deprecate `part()`. (TooTallNate)
* Set default user-agent header. (bevacqua)
* Add `unset()` method for removing headers. (bevacqua)
* Update cookiejar. (missinglink)
* Fix response error formatting. (shesek)

# 0.17.0 / 2014-03-06

* supply uri malformed error to the callback (yields)
* add request event (yields)
* allow simple auth (yields)
* add request event (yields)
* switch to component/reduce (visionmedia)
* fix part content-disposition (mscdex)
* add browser testing via zuul (defunctzombie)
* adds request.use() (johntron)

# 0.16.0 / 2014-01-07

* remove support for 0.6 (superjoe30)
* fix CORS withCredentials (wejendorp)
* add "test" script (superjoe30)
* add request .accept() method (nickl-)
* add xml to mime types mappings (nickl-)
* fix parse body error on HEAD requests (gjohnson)
* fix documentation typos (matteofigus)
* fix content-type + charset (bengourley)
* fix null values on query parameters (cristiandouce)

# 0.15.7 / 2013-10-19

* pin should.js to 1.3.0 due to breaking change in 2.0.x
* fix browserify regression

# 0.15.5 / 2013-10-09

* add browser field to support browserify
* fix .field() value number support

# 0.15.4 / 2013-07-09

* node: add a Request#agent() function to set the http Agent to use

# 0.15.3 / 2013-07-05

* fix .pipe() unzipping on more recent nodes. Closes [#240](https://github.com/ladjs/superagent/issues/240)
* fix passing an empty object to .query() no longer appends "?"
* fix formidable error handling
* update formidable

# 0.15.2 / 2013-07-02

* fix: emit 'end' when piping.

# 0.15.1 / 2013-06-26

* add try/catch around parseLinks

# 0.15.0 / 2013-06-25

* make `Response#toError()` have a more meaningful `message`

# 0.14.9 / 2013-06-15

* add debug()s to the node client
* add .abort() method to node client

# 0.14.8 / 2013-06-13

* set .agent = false always
* remove X-Requested-With. Closes [#189](https://github.com/ladjs/superagent/issues/189)

# 0.14.7 / 2013-06-06

* fix unzip error handling

# 0.14.6 / 2013-05-23

* fix HEAD unzip bug

# 0.14.5 / 2013-05-23

* add flag to ensure the callback is **never** invoked twice

# 0.14.4 / 2013-05-22

* add superagent.js build output
* update qs
* update emitter-component
* revert "add browser field to support browserify" see [GH-221](https://github.com/ladjs/superagent/issues/221)

# 0.14.3 / 2013-05-18

* add browser field to support browserify

# 0.14.2/ 2013-05-07

* add host object check to fix serialization of File/Blobs etc as json

# 0.14.1 / 2013-04-09

* update qs

# 0.14.0 / 2013-04-02

* add client-side basic auth
* fix retaining of .set() header field case

# 0.13.0 / 2013-03-13

* add progress events to client
* add simple example
* add res.headers as alias of res.header for browser client
* add res.get(field) to node/client

# 0.12.4 / 2013-02-11

* fix get content-type even if can't get other headers in firefox. fixes [#181](https://github.com/ladjs/superagent/issues/181)

# 0.12.3 / 2013-02-11

* add quick "progress" event support

# 0.12.2 / 2013-02-04

* add test to check if response acts as a readable stream
* add ReadableStream in the Response prototype.
* add test to assert correct redirection when the host changes in the location header.
* add default Accept-Encoding. Closes [#155](https://github.com/ladjs/superagent/issues/155)
* fix req.pipe() return value of original stream for node parity. Closes [#171](https://github.com/ladjs/superagent/issues/171)
* remove the host header when cleaning headers to properly follow the redirection.

# 0.12.1 / 2013-01-10

* add x-domain error handling

# 0.12.0 / 2013-01-04

* add header persistence on redirects

# 0.11.0 / 2013-01-02

* add .error Error object. Closes [#156](https://github.com/ladjs/superagent/issues/156)
* add forcing of res.text removal for FF HEAD responses. Closes [#162](https://github.com/ladjs/superagent/issues/162)
* add reduce component usage. Closes [#90](https://github.com/ladjs/superagent/issues/90)
* move better-assert dep to development deps

# 0.10.0 / 2012-11-14

* add req.timeout(ms) support for the client

# 0.9.10 / 2012-11-14

* fix client-side .query(str) support

# 0.9.9 / 2012-11-14

* add .parse(fn) support
* fix socket hangup with dates in querystring. Closes [#146](https://github.com/ladjs/superagent/issues/146)
* fix socket hangup "error" event when a callback of arity 2 is provided

# 0.9.8 / 2012-11-03

* add emission of error from `Request#callback()`
* add a better fix for nodes weird socket hang up error
* add PUT/POST/PATCH data support to client short-hand functions
* add .license property to component.json
* change client portion to build using component(1)
* fix GET body support [guille]

# 0.9.7 / 2012-10-19

* fix `.buffer()` `res.text` when no parser matches

# 0.9.6 / 2012-10-17

* change: use `this` when `window` is undefined
* update to new component spec [juliangruber]
* fix emission of "data" events for compressed responses without encoding. Closes [#125](https://github.com/ladjs/superagent/issues/125)

# 0.9.5 / 2012-10-01

* add field name to .attach()
* add text "parser"
* refactor isObject()
* remove wtf isFunction() helper

# 0.9.4 / 2012-09-20

* fix `Buffer` responses [TooTallNate]
* fix `res.type` when a "type" param is present [TooTallNate]

# 0.9.3 / 2012-09-18

* remove **GET** `.send()` == `.query()` special-case (**API** change !!!)

# 0.9.2 / 2012-09-17

* add `.aborted` prop
* add `.abort()`. Closes [#115](https://github.com/ladjs/superagent/issues/115)

# 0.9.1 / 2012-09-07

* add `.forbidden` response property
* add component.json
* change emitter-component to 0.0.5
* fix client-side tests

# 0.9.0 / 2012-08-28

* add `.timeout(ms)`. Closes [#17](https://github.com/ladjs/superagent/issues/17)

# 0.8.2 / 2012-08-28

* fix pathname relative redirects. Closes [#112](https://github.com/ladjs/superagent/issues/112)

# 0.8.1 / 2012-08-21

* fix redirects when schema is specified

# 0.8.0 / 2012-08-19

* add `res.buffered` flag
* add buffering of text/\*, json and forms only by default. Closes [#61](https://github.com/ladjs/superagent/issues/61)
* add `.buffer(false)` cancellation
* add cookie jar support [hunterloftis]
* add agent functionality [hunterloftis]

# 0.7.0 / 2012-08-03

* allow `query()` to be called after the internal `req` has been created [tootallnate]

# 0.6.0 / 2012-07-17

* add `res.send('foo=bar')` default of "application/x-www-form-urlencoded"

# 0.5.1 / 2012-07-16

* add "methods" dep
* add `.end()` arity check to node callbacks
* fix unzip support due to weird node internals

# 0.5.0 / 2012-06-16

* Added "Link" response header field parsing, exposing `res.links`

# 0.4.3 / 2012-06-15

* Added 303, 305 and 307 as redirect status codes [slaskis]
* Fixed passing an object as the url

# 0.4.2 / 2012-06-02

* Added component support
* Fixed redirect data

# 0.4.1 / 2012-04-13

* Added HTTP PATCH support
* Fixed: GET / HEAD when following redirects. Closes [#86](https://github.com/ladjs/superagent/issues/86)
* Fixed Content-Length detection for multibyte chars

# 0.4.0 / 2012-03-04

* Added `.head()` method [browser]. Closes [#78](https://github.com/ladjs/superagent/issues/78)
* Added `make test-cov` support
* Added multipart request support. Closes [#11](https://github.com/ladjs/superagent/issues/11)
* Added all methods that node supports. Closes [#71](https://github.com/ladjs/superagent/issues/71)
* Added "response" event providing a Response object. Closes [#28](https://github.com/ladjs/superagent/issues/28)
* Added `.query(obj)`. Closes [#59](https://github.com/ladjs/superagent/issues/59)
* Added `res.type` (browser). Closes [#54](https://github.com/ladjs/superagent/issues/54)
* Changed: default `res.body` and `res.files` to {}
* Fixed: port existing query-string fix (browser). Closes [#57](https://github.com/ladjs/superagent/issues/57)

# 0.3.0 / 2012-01-24

* Added deflate/gzip support [guillermo]
* Added `res.type` (Content-Type void of params)
* Added `res.statusCode` to mirror node
* Added `res.headers` to mirror node
* Changed: parsers take callbacks
* Fixed optional schema support. Closes [#49](https://github.com/ladjs/superagent/issues/49)

# 0.2.0 / 2012-01-05

* Added url auth support
* Added `.auth(username, password)`
* Added basic auth support [node]. Closes [#41](https://github.com/ladjs/superagent/issues/41)
* Added `make test-docs`
* Added guillermo's EventEmitter. Closes [#16](https://github.com/ladjs/superagent/issues/16)
* Removed `Request#data()` for SS, renamed to `send()`
* Removed `Request#data()` from client, renamed to `send()`
* Fixed array support. [browser]
* Fixed array support. Closes [#35](https://github.com/ladjs/superagent/issues/35) [node]
* Fixed `EventEmitter#emit()`

# 0.1.3 / 2011-10-25

* Added error to callback
* Bumped node dep for 0.5.x

# 0.1.2 / 2011-09-24

* Added markdown documentation
* Added `request(url[, fn])` support to the client
* Added `qs` dependency to package.json
* Added options for `Request#pipe()`
* Added support for `request(url, callback)`
* Added `request(url)` as shortcut for `request.get(url)`
* Added `Request#pipe(stream)`
* Added inherit from `Stream`
* Added multipart support
* Added ssl support (node)
* Removed Content-Length field from client
* Fixed buffering, `setEncoding()` to utf8 [reported by stagas]
* Fixed "end" event when piping

# 0.1.1 / 2011-08-20

* Added `res.redirect` flag (node)
* Added redirect support (node)
* Added `Request#redirects(n)` (node)
* Added `.set(object)` header field support
* Fixed `Content-Length` support

# 0.1.0 / 2011-08-09

* Added support for multiple calls to `.data()`
* Added support for `.get(uri, obj)`
* Added GET `.data()` querystring support
* Added IE{6,7,8} support [alexyoung]

# 0.0.1 / 2011-08-05

* Initial commit





================================================
FILE: LICENSE
================================================
(The MIT License)

Copyright (c) 2014-2016 TJ Holowaychuk <tj@vision-media.ca>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
OLDNODETESTS ?= lib/node/test/*.js lib/node/test/node/*.js
NODETESTS ?= test/*.js test/node/*.js
BROWSERTESTS ?= test/*.js test/client/*.js
REPORTER = spec

ifeq ("$(OLD_NODE_TEST)", "1")
	NODETESTS := $(OLDNODETESTS)
endif

test:
	@if [ "$(BROWSER)" = "1" ]; then \
		echo test on browser; \
		make test-browser; \
	fi \

	@if [ "$(NODE_TEST)" = "1" ] || [ "x$(BROWSER)" = "x" ]; then \
    echo test on node with http1; \
    export HTTP2_TEST="" && make test-node; \
    if [ "$(HTTP2_TEST_DISABLED)" != "1" ]; then \
      echo test on node with http2; \
      export HTTP2_TEST="1" && make test-node; \
    fi \
	fi

copy:
	@if [ "$(OLD_NODE_TEST)" = "1" ]; then \
		echo test on old node; \
		cp test/node/fixtures lib/node/test/node -rf; \
	else \
		echo test on plain node; \
	fi

test-node:copy
	@NODE_ENV=test HTTP2_TEST=$(HTTP2_TEST) ./node_modules/.bin/nyc ./node_modules/.bin/mocha \
		--require should \
		--trace-warnings \
		--throw-deprecation \
		--reporter $(REPORTER) \
		--slow 2000 \
		--timeout 5000 \
		--exit \
		$(NODETESTS)

test-cov: lib-cov
	SUPERAGENT_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html

test-browser:
	SAUCE_APPIUM_VERSION=1.7 ./node_modules/.bin/zuul -- $(BROWSERTESTS)

test-browser-local:
	./node_modules/.bin/zuul --no-coverage --local 4000 -- $(BROWSERTESTS)

lib-cov:
	jscoverage lib lib-cov

test-server:
	@node test/server

docs: index.html test-docs docs/index.md

index.html: docs/index.md docs/head.html docs/tail.html
	marked < $< \
		| cat docs/head.html - docs/tail.html \
		> $@

docclean:
	rm -f index.html docs/test.html

test-docs: docs/head.html docs/tail.html
	make test REPORTER=doc \
		| cat docs/head.html - docs/tail.html \
		> docs/test.html

clean:
	rm -fr components

.PHONY: copy test-cov test docs test-docs clean test-browser-local


================================================
FILE: README.md
================================================
# superagent

[![build status](https://github.com/forwardemail/superagent/actions/workflows/ci.yml/badge.svg)](https://github.com/forwardemail/superagent/actions/workflows/ci.yml)
[![code coverage](https://img.shields.io/codecov/c/github/ladjs/superagent.svg)](https://codecov.io/gh/ladjs/superagent)
[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)
[![license](https://img.shields.io/github/license/ladjs/superagent.svg)](LICENSE)

> 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).


## Table of Contents

* [Install](#install)
* [Usage](#usage)
  * [Node](#node)
  * [Browser](#browser)
* [Supported Platforms](#supported-platforms)
  * [Required Browser Features](#required-browser-features)
* [Plugins](#plugins)
* [Upgrading from previous versions](#upgrading-from-previous-versions)
* [Contributors](#contributors)
* [License](#license)


## Install

[npm][]:

```sh
npm install superagent
```

[yarn][]:

```sh
yarn add superagent
```


## Usage

### Node

```js
const superagent = require('superagent');

// callback
superagent
  .post('/api/pet')
  .send({ name: 'Manny', species: 'cat' }) // sends a JSON post body
  .set('X-API-Key', 'foobar')
  .set('accept', 'json')
  .end((err, res) => {
    // Calling the end function will send the request
  });

// promise with then/catch
superagent.post('/api/pet').then(console.log).catch(console.error);

// promise with async/await
(async () => {
  try {
    const res = await superagent.post('/api/pet');
    console.log(res);
  } catch (err) {
    console.error(err);
  }
})();
```

### Browser

**The browser-ready, minified version of `superagent` is only 50 KB (minified and gzipped).**

Browser-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.

> Note that we also provide unminified versions with `.js` instead of `.min.js` file extensions.

#### VanillaJS

This is the solution for you if you're just using `<script>` tags everywhere!

```html
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt"></script>
<script src="https://cdn.jsdelivr.net/npm/superagent"></script>
<!-- if you wish to use unpkg.com instead: -->
<!-- <script src="https://unpkg.com/superagent"></script> -->
<script type="text/javascript">
  (function() {
    // superagent is exposed as `window.superagent`
    // if you wish to use "request" instead please
    // uncomment the following line of code:
    // `window.request = superagent;`
    superagent
      .post('/api/pet')
      .send({ name: 'Manny', species: 'cat' }) // sends a JSON post body
      .set('X-API-Key', 'foobar')
      .set('accept', 'json')
      .end(function (err, res) {
        // Calling the end function will send the request
      });
  })();
</script>
```

#### Bundler

If you are using [browserify][], [webpack][], [rollup][], or another bundler, then you can follow the same usage as [Node](#node) above.


## Supported Platforms

* Node: v14.18.0+
* Browsers (see [.browserslistrc](.browserslistrc)):

  ```sh
  npx browserslist
  ```

  ```sh
  and_chr 102
  and_ff 101
  and_qq 10.4
  and_uc 12.12
  android 101
  chrome 103
  chrome 102
  chrome 101
  chrome 100
  edge 103
  edge 102
  edge 101
  firefox 101
  firefox 100
  firefox 91
  ios_saf 15.5
  ios_saf 15.4
  ios_saf 15.2-15.3
  ios_saf 15.0-15.1
  ios_saf 14.5-14.8
  ios_saf 14.0-14.4
  ios_saf 12.2-12.5
  kaios 2.5
  op_mini all
  op_mob 64
  opera 86
  opera 85
  safari 15.5
  safari 15.4
  samsung 17.0
  samsung 16.0
  ```

### Required Browser Features

We recommend using <https://cdnjs.cloudflare.com/polyfill/> (specifically with the bundle mentioned in [VanillaJS](#vanillajs) above):

```html
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt"></script>
```

* WeakRef is not supported in Opera 85, iOS Safari 12.2-12.5
* BigInt is not supported in iOS Safari 12.2-12.5


## Plugins

SuperAgent is easily extended via plugins.

```js
const nocache = require('superagent-no-cache');
const superagent = require('superagent');
const prefix = require('superagent-prefix')('/static');

superagent
  .get('/some-url')
  .query({ action: 'edit', city: 'London' }) // query string
  .use(prefix) // Prefixes *only* this request
  .use(nocache) // Prevents caching of *only* this request
  .end((err, res) => {
    // Do something
  });
```

Existing plugins:

* [superagent-no-cache](https://github.com/johntron/superagent-no-cache) - prevents caching by including Cache-Control header
* [superagent-prefix](https://github.com/johntron/superagent-prefix) - prefixes absolute URLs (useful in test environment)
* [superagent-suffix](https://github.com/timneutkens1/superagent-suffix) - suffix URLs with a given path
* [superagent-mock](https://github.com/M6Web/superagent-mock) - simulate HTTP calls by returning data fixtures based on the requested URL
* [superagent-mocker](https://github.com/shuvalov-anton/superagent-mocker) — simulate REST API
* [superagent-cache](https://github.com/jpodwys/superagent-cache) - A global SuperAgent patch with built-in, flexible caching
* [superagent-cache-plugin](https://github.com/jpodwys/superagent-cache-plugin) - A SuperAgent plugin with built-in, flexible caching
* [superagent-jsonapify](https://github.com/alex94puchades/superagent-jsonapify) - A lightweight [json-api](http://jsonapi.org/format/) client addon for superagent
* [superagent-serializer](https://github.com/zzarcon/superagent-serializer) - Converts server payload into different cases
* [superagent-httpbackend](https://www.npmjs.com/package/superagent-httpbackend) - stub out requests using AngularJS' $httpBackend syntax
* [superagent-throttle](https://github.com/leviwheatcroft/superagent-throttle) - queues and intelligently throttles requests
* [superagent-charset](https://github.com/magicdawn/superagent-charset) - add charset support for node's SuperAgent
* [superagent-verbose-errors](https://github.com/jcoreio/superagent-verbose-errors) - include response body in error messages for failed requests
* [superagent-declare](https://github.com/damoclark/superagent-declare) - A simple [declarative](https://en.wikipedia.org/wiki/Declarative_programming) API for SuperAgent
* [superagent-node-http-timings](https://github.com/webuniverseio/superagent-node-http-timings) - measure http timings in node.js
* [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.
* [@certible/superagent-aws-sign](https://github.com/certible/superagent-aws-sign) - Sign AWS endpoint requests, it uses the aws4 to authenticate the SuperAgent requests

Please prefix your plugin with `superagent-*` so that it can easily be found by others.

For SuperAgent extensions such as couchdb and oauth visit the [wiki](https://github.com/ladjs/superagent/wiki).


## Upgrading from previous versions

Please see [GitHub releases page](https://github.com/ladjs/superagent/releases) for the current changelog.

Our breaking changes are mostly in rarely used functionality and from stricter error handling.

* [6.0 to 6.1](https://github.com/ladjs/superagent/releases/tag/v6.1.0)
  * 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>)
* [5.x to 6.x](https://github.com/ladjs/superagent/releases/tag/v6.0.0):
  * 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)
  * A specific issue with Content-Type matching not being case-insensitive is fixed
  * Set is now required for IE 9, see [Required Browser Features](#required-browser-features) for more insight
* [4.x to 5.x](https://github.com/ladjs/superagent/releases/tag/v5.0.0):
  * We've implemented the build setup of [Lass](https://lass.js.org) to simplify our stack and linting
  * 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`)
  * Linting support has been added using `caniuse-lite` and `eslint-plugin-compat`
  * We can now target what versions of Node we wish to support more easily using `.babelrc`
* [3.x to 4.x](https://github.com/ladjs/superagent/releases/tag/v4.0.0-alpha.1):
  * Ensure you're running Node 6 or later. We've dropped support for Node 4.
  * We've started using ES6 and for compatibility with Internet Explorer you may need to use Babel.
  * We suggest migrating from `.end()` callbacks to `.then()` or `await`.
* [2.x to 3.x](https://github.com/ladjs/superagent/releases/tag/v3.0.0):
  * Ensure you're running Node 4 or later. We've dropped support for Node 0.x.
  * Test code that calls `.send()` multiple times. Invalid calls to `.send()` will now throw instead of sending garbage.
* [1.x to 2.x](https://github.com/ladjs/superagent/releases/tag/v2.0.0):
  * If you use `.parse()` in the *browser* version, rename it to `.serialize()`.
  * 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).
  * If you use `.then()` in Internet Explorer, ensure that you have a polyfill that adds a global `Promise` object.
* 0.x to 1.x:
  * Instead of 1-argument callback `.end(function(res){})` use `.then(res => {})`.


## Contributors

| Name                |
| ------------------- |
| **Kornel Lesiński** |
| **Peter Lyons**     |
| **Hunter Loftis**   |
| **Nick Baugh**      |


## License

[MIT](LICENSE) © TJ Holowaychuk


##

[npm]: https://www.npmjs.com/

[yarn]: https://yarnpkg.com/

[jsdelivr]: https://www.jsdelivr.com/

[unpkg]: https://unpkg.com/

[browserify]: https://github.com/browserify/browserify

[webpack]: https://github.com/webpack/webpack

[rollup]: https://github.com/rollup/rollup


================================================
FILE: SECURITY.md
================================================
# Security Policy


## Reporting a Vulnerability

Please report security issues to `niftylettuce@gmail.com`


================================================
FILE: ci/remove-deps-4-old-node.js
================================================
const fs = require('fs');
const path = require('path');
const package = require('../package.json');

const UNSUPPORT_DEPS_4_OLD = new Set([
  '@commitlint/cli',
  '@commitlint/config-conventional',
  'eslint',
  'eslint-config-xo-lass',
  'eslint-plugin-compat',
  'eslint-plugin-node',
  'husky',
  'lint-staged',
  'marked',
  'remark-cli',
  'remark-preset-github',
  'xo'
]);

for (const item in package.devDependencies) {
  if (UNSUPPORT_DEPS_4_OLD.has(item)) {
    package.devDependencies[item] = undefined;
  }
}

fs.writeFileSync(
  path.join(__dirname, '../package.json'),
  JSON.stringify(package, null, 2)
);


================================================
FILE: docs/head.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8">
    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css">
    <link rel="stylesheet" href="docs/style.css">
  </head>
  <body>
    <ul id="menu"></ul>
    <div id="content">


================================================
FILE: docs/index.md
================================================

# SuperAgent

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!

```javascript
     request
       .post('/api/pet')
       .send({ name: 'Manny', species: 'cat' })
       .set('X-API-Key', 'foobar')
       .set('Accept', 'application/json')
       .then(res => {
          alert('yay got ' + JSON.stringify(res.body));
       });
```

## Test documentation

[**中文文档**](docs/zh_CN/index.html)

The 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.

## Request basics

A 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:

```javascript
     request
       .get('/search')
       .then(res => {
          // res.body, res.headers, res.status
       })
       .catch(err => {
          // err.message, err.response
       });
```

HTTP method may also be passed as a string:

```javascript
    request('GET', '/search').then(success, failure);
```

Old-style callbacks are also supported, but not recommended. *Instead of* `.then()` you can call `.end()`:

```javascript
    request('GET', '/search').end(function(err, res){
      if (res.ok) {}
    });
```

Absolute URLs can be used. In web browsers absolute URLs work only if the server implements [CORS](#cors).

```javascript
     request
       .get('https://example.com/search')
       .then(res => {

       });
```

The __Node__ client supports making requests to [Unix Domain Sockets](https://en.wikipedia.org/wiki/Unix_domain_socket):

```javascript
    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH
    //          Use `%2F` as `/` in SOCKET_PATH
    try {
      const res = await request
        .get('http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search');
      // res.body, res.headers, res.status
    } catch(err) {
      // err.message, err.response
    }
```

__DELETE__, __HEAD__, __PATCH__, __POST__, and __PUT__ requests can also be used, simply change the method name:

```javascript
    request
      .head('/favicon.ico')
      .then(res => {

      });
```

__DELETE__ can be also called as `.del()` for compatibility with old IE where `delete` is a reserved word.

The HTTP method defaults to __GET__, so if you wish, the following is valid:

```javascript
     request('/search', (err, res) => {

     });
```

## Using HTTP/2

To make a request using HTTP/2 protocol only (with no HTTP/1.x fallback), use the `.http2()` method.

```javascript
    const request = require('superagent');
    const res = await request
      .get('https://example.com/h2')
      .http2();
```

## Setting header fields

Setting header fields is simple, invoke `.set()` with a field name and value:

```javascript
     request
       .get('/search')
       .set('API-Key', 'foobar')
       .set('Accept', 'application/json')
       .then(callback);
```

You may also pass an object to set several fields in a single call:

```javascript
     request
       .get('/search')
       .set({ 'API-Key': 'foobar', Accept: 'application/json' })
       .then(callback);
```

## `GET` requests

The `.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`.

```javascript
     request
       .get('/search')
       .query({ query: 'Manny' })
       .query({ range: '1..5' })
       .query({ order: 'desc' })
       .then(res => {

       });
```

Or as a single object:

```javascript
    request
      .get('/search')
      .query({ query: 'Manny', range: '1..5', order: 'desc' })
      .then(res => {

      });
```

The `.query()` method accepts strings as well:

```javascript
      request
        .get('/querystring')
        .query('search=Manny&range=1..5')
        .then(res => {

        });
```

Or joined:

```javascript
      request
        .get('/querystring')
        .query('search=Manny')
        .query('range=1..5')
        .then(res => {

        });
```

## `HEAD` requests

You can also use the `.query()` method for HEAD requests. The following will produce the path `/users?email=joe@smith.com`.

```javascript
      request
        .head('/users')
        .query({ email: 'joe@smith.com' })
        .then(res => {

        });
```

## `POST` / `PUT` requests

A 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.

```javascript
      request.post('/user')
        .set('Content-Type', 'application/json')
        .send('{"name":"tj","pet":"tobi"}')
        .then(callback)
        .catch(errorCallback)
```

Since JSON is undoubtedly the most common, it's the _default_! The following example is equivalent to the previous.

```javascript
      request.post('/user')
        .send({ name: 'tj', pet: 'tobi' })
        .then(callback, errorCallback)
```

Or using multiple `.send()` calls:

```javascript
      request.post('/user')
        .send({ name: 'tj' })
        .send({ pet: 'tobi' })
        .then(callback, errorCallback)
```

By default sending strings will set the `Content-Type` to `application/x-www-form-urlencoded`,
  multiple calls will be concatenated with `&`, here resulting in `name=tj&pet=tobi`:

```javascript
      request.post('/user')
        .send('name=tj')
        .send('pet=tobi')
        .then(callback, errorCallback);
```

SuperAgent 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".

```javascript
      request.post('/user')
        .type('form')
        .send({ name: 'tj' })
        .send({ pet: 'tobi' })
        .then(callback, errorCallback)
```

Sending 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":

```javascript
      request.post('/user')
        .send(new FormData(document.getElementById('myForm')))
        .then(callback, errorCallback)
```

## Setting the `Content-Type`

The obvious solution is to use the `.set()` method:

```javascript
     request.post('/user')
       .set('Content-Type', 'application/json')
```

As a short-hand the `.type()` method is also available, accepting
the canonicalized MIME type name complete with type/subtype, or
simply the extension name such as "xml", "json", "png", etc:

```javascript
     request.post('/user')
       .type('application/json')

     request.post('/user')
       .type('json')

     request.post('/user')
       .type('png')
```

## Serializing request body

SuperAgent will automatically serialize JSON and forms.
You can setup automatic serialization for other types as well:

```js
request.serialize['application/xml'] = function (obj) {
    return 'string generated from obj';
};

// going forward, all requests with a Content-type of
// 'application/xml' will be automatically serialized
```
If you want to send the payload in a custom format, you can replace
the built-in serialization with the `.serialize()` method on a per-request basis:

```js
request
    .post('/user')
    .send({foo: 'bar'})
    .serialize(obj => {
        return 'string generated from obj';
    });
```
## Retrying requests

When 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.

This 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).

```javascript
     request
       .get('https://example.com/search')
       .retry(2) // or:
       .retry(2, callback)
       .then(finished);
       .catch(failed);
```

Use `.retry()` only with requests that are *idempotent* (i.e. multiple requests reaching the server won't cause undesirable side effects like duplicate purchases).

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).

By default the following status codes are retried:

* `408`
* `413`
* `429`
* `500`
* `502`
* `503`
* `504`
* `521`
* `522`
* `524`

By default the following error codes are retried:

* `'ETIMEDOUT'`
* `'ECONNRESET'`
* `'EADDRINUSE'`
* `'ECONNREFUSED'`
* `'EPIPE'`
* `'ENOTFOUND'`
* `'ENETUNREACH'`
* `'EAI_AGAIN'`

## Setting Accept

In 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:

```javascript
     request.get('/user')
       .accept('application/json')

     request.get('/user')
       .accept('json')

     request.post('/user')
       .accept('png')
```

### Facebook and Accept JSON

If 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.

## Query strings

  `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__:

```javascript
    request
      .post('/')
      .query({ format: 'json' })
      .query({ dest: '/login' })
      .send({ post: 'data', here: 'wahoo' })
      .then(callback);
```

By 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.

```js
 // default order
 request.get('/user')
   .query('name=Nick')
   .query('search=Manny')
   .sortQuery()
   .then(callback)

 // customized sort function
 request.get('/user')
   .query('name=Nick')
   .query('search=Manny')
   .sortQuery((a, b) => a.length - b.length)
   .then(callback)
```

## TLS options

In Node.js SuperAgent supports methods to configure HTTPS requests:

- `.ca()`: Set the CA certificate(s) to trust
- `.cert()`: Set the client certificate chain(s)
- `.key()`: Set the client private key(s)
- `.pfx()`: Set the client PFX or PKCS12 encoded private key and certificate chain
- `.disableTLSCerts()`: Does not reject expired or invalid TLS certs. Sets internally `rejectUnauthorized=true`. *Be warned, this method allows MITM attacks.*

For more information, see Node.js [https.request docs](https://nodejs.org/api/https.html#https_https_request_options_callback).

```js
var key = fs.readFileSync('key.pem'),
    cert = fs.readFileSync('cert.pem');

request
  .post('/client-auth')
  .key(key)
  .cert(cert)
  .then(callback);
```

```js
var ca = fs.readFileSync('ca.cert.pem');

request
  .post('https://localhost/private-ca-server')
  .ca(ca)
  .then(res => {});
```

## Parsing response bodies

SuperAgent will parse known response-body data for you,
currently supporting `application/x-www-form-urlencoded`,
`application/json`, and `multipart/form-data`. You can setup
automatic parsing for other response-body data as well:

```js
//browser
request.parse['application/xml'] = function (str) {
    return {'object': 'parsed from str'};
};

//node
request.parse['application/xml'] = function (res, cb) {
    //parse response text and set res.body here

    cb(null, res);
};

//going forward, responses of type 'application/xml'
//will be parsed automatically
```

You 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.

### JSON / Urlencoded

The 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.

Arrays 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.

### Multipart

The 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:

    --whoop
    Content-Disposition: attachment; name="image"; filename="tobi.png"
    Content-Type: image/png

    ... data here ...
    --whoop
    Content-Disposition: form-data; name="name"
    Content-Type: text/plain

    Tobi
    --whoop--

You 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.

### Binary

In 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

- `'blob'` passed through to the XmlHTTPRequest `responseType` property
- `'arraybuffer'` passed through to the XmlHTTPRequest `responseType` property

```js
req.get('/binary.data')
  .responseType('blob')
  .then(res => {
    // res.body will be a browser native Blob type here
  });
```

For more information, see the Mozilla Developer Network [xhr.responseType docs](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).

## Response properties

Many helpful flags and properties are set on the `Response` object, ranging from the response text, parsed response body, header fields, status flags and more.

### Response text

The `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.

### Response body

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 "application/json" and "application/x-www-form-urlencoded". The parsed object is then available via `res.body`.

### Response header fields

The `res.header` contains an object of parsed header fields, lowercasing field names much like node does. For example `res.header['content-length']`.

### Response Content-Type

The 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".

### Response status

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:

```javascript
     var type = status / 100 | 0;

     // status / class
     res.status = status;
     res.statusType = type;

     // basics
     res.info = 1 == type;
     res.ok = 2 == type;
     res.clientError = 4 == type;
     res.serverError = 5 == type;
     res.error = 4 == type || 5 == type;

     // sugar
     res.accepted = 202 == status;
     res.noContent = 204 == status || 1223 == status;
     res.badRequest = 400 == status;
     res.unauthorized = 401 == status;
     res.notAcceptable = 406 == status;
     res.notFound = 404 == status;
     res.forbidden = 403 == status;
```

## Aborting requests

To abort requests simply invoke the `req.abort()` method.

## Timeouts

Sometimes networks and servers get "stuck" and never respond after accepting a request. Set timeouts to avoid requests waiting forever.

  * `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.

  * `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.

You 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.

```javascript
    request
      .get('/big-file?network=slow')
      .timeout({
        response: 5000,  // Wait 5 seconds for the server to start sending,
        deadline: 60000, // but allow 1 minute for the file to finish loading.
      })
      .then(res => {
          /* responded in time */
        }, err => {
          if (err.timeout) { /* timed out! */ } else { /* other error */ }
      });
```

Timeout errors have a `.timeout` property.

## Authentication

In both Node and browsers auth available via the `.auth()` method:

```javascript
    request
      .get('http://local')
      .auth('tobi', 'learnboost')
      .then(callback);
```

In the _Node_ client Basic auth can be in the URL as "user:pass":

```javascript
    request.get('http://tobi:learnboost@local').then(callback);
```

By 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.):

```javascript
    request.auth('digest', 'secret', {type:'auto'})
```

The `auth` method also supports a `type` of `bearer`, to specify token-based authentication:

```javascript
    request.auth('my_token', { type: 'bearer' })
```

## Following redirects

By default up to 5 redirects will be followed, however you may specify this with the `res.redirects(n)` method:

```javascript
    const response = await request.get('/some.png').redirects(2);
```

Redirects exceeding the limit are treated as errors. Use `.ok(res => res.status < 400)` to read them as successful responses.

## Agents for global state

### Saving cookies

In 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.

```javascript
    const agent = request.agent();
    agent
      .post('/login')
      .then(() => {
        return agent.get('/cookied-page');
      });
```

In browsers cookies are managed automatically by the browser, so the `.agent()` does not isolate cookies.

### Default options for multiple requests

Regular request methods called on the agent will be used as defaults for all requests made by that agent.

```javascript
    const agent = request.agent()
      .use(plugin)
      .auth(shared);

    await agent.get('/with-plugin-and-auth');
    await agent.get('/also-with-plugin-and-auth');
```

The 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`.

## Piping data

The Node client allows you to pipe data to and from the request. Please note that `.pipe()` is used **instead of** `.end()`/`.then()` methods.

For example piping a file's contents as the request:

```javascript
    const request = require('superagent');
    const fs = require('fs');

    const stream = fs.createReadStream('path/to/my.json');
    const req = request.post('/somewhere');
    req.type('json');
    stream.pipe(req);
```

Note 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).

Or piping the response to a file:

```javascript
    const stream = fs.createWriteStream('path/to/my.json');
    const req = request.get('/some.json');
    req.pipe(stream);
```

 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:

```javascript
    // Don't do either of these:
    const stream = getAWritableStream();
    const req = request
      .get('/some.json')
      // BAD: this pipes garbage to the stream and fails in unexpected ways
      .end((err, this_does_not_work) => this_does_not_work.pipe(stream))
    const req = request
      .get('/some.json')
      .end()
      // BAD: this is also unsupported, .pipe calls .end for you.
      .pipe(nope_its_too_late);
```

In a [future version](https://github.com/ladjs/superagent/issues/1188) of superagent, improper calls to `pipe()` will fail.

## Multipart requests

SuperAgent is also great for _building_ multipart requests for which it provides methods `.attach()` and `.field()`.

When 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).

### Attaching files

To send a file use `.attach(name, [file], [options])`. You can attach multiple files by calling `.attach` multiple times. The arguments are:

 * `name` — field name in the form.
 * `file` — either string with file path or `Blob`/`Buffer` object.
 * `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.

<br>

```javascript
    request
      .post('/upload')
      .attach('image1', 'path/to/felix.jpeg')
      .attach('image2', imageBuffer, 'luna.jpeg')
      .field('caption', 'My cats')
      .then(callback);
```

### Field values

Much 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:

```javascript
     request
       .post('/upload')
       .field('user[name]', 'Tobi')
       .field('user[email]', 'tobi@learnboost.com')
       .field('friends[]', ['loki', 'jane'])
       .attach('image', 'path/to/tobi.png')
       .then(callback);
```

## Compression

The node client supports compressed responses, best of all, you don't have to do anything! It just works.

## Buffering responses

To 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)`.

When buffered the `res.buffered` flag is provided, you may use this to handle both buffered and unbuffered responses in the same callback.

## CORS

For 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).

The `.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".

```javascript
    request
      .get('https://api.example.com:4001/')
      .withCredentials()
      .then(res => {
        assert.equal(200, res.status);
        assert.equal('tobi', res.text);
      })
```

## Error handling

Your callback function will always be passed two arguments: error and response. If no error occurred, the first argument will be null:

```javascript
    request
     .post('/upload')
     .attach('image', 'path/to/tobi.png')
     .then(res => {

     });
```

An "error" event is also emitted, with you can listen for:

```javascript
    request
      .post('/upload')
      .attach('image', 'path/to/tobi.png')
      .on('error', handle)
      .then(res => {

      });
```

Note 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.

Network failures, timeouts, and other errors that produce no response will contain no `err.status` or `err.response` fields.

If 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:

```javascript
    if (err && err.status === 404) {
      alert('oh no ' + res.body.message);
    }
    else if (err) {
      // all other error types we handle generically
    }
```

Alternatively, 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.

```javascript
    request.get('/404')
      .ok(res => res.status < 500)
      .then(response => {
        // reads 404 page as a successful response
      })
```

## Progress tracking

SuperAgent fires `progress` events on upload and download of large files.

```javascript
    request.post(url)
      .attach('field_name', file)
      .on('progress', event => {
        /* the event is:
        {
          direction: "upload" or "download"
          percent: 0 to 100 // may be missing if file size is unknown
          total: // total file size, may be missing
          loaded: // bytes downloaded or uploaded so far
        } */
      })
      .then()
```

## Testing on localhost

### Forcing specific connection IP address

In 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`:

```javascript
    const res = await request.get("http://example.com").connect("127.0.0.1");
```

Because 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.

```javascript
    const res = await request.get("http://redir.example.com:555")
      .connect({
        "redir.example.com": "127.0.0.1", // redir.example.com:555 will use 127.0.0.1:555
        "www.example.com": false, // don't override this one; use DNS as normal
        "mapped.example.com": { host: "127.0.0.1", port: 8080}, // mapped.example.com:* will use 127.0.0.1:8080
        "*": "proxy.example.com", // all other requests will go to this host
      });
```

### Ignoring broken/insecure HTTPS on localhost

In 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()`:

```javascript
    const res = await request.get("https://localhost").trustLocalhost()
```

Together with `.connect("127.0.0.1")` this may be used to force HTTPS requests to any domain to be re-routed to `localhost` instead.

It'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.

We 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.

## Promise and Generator support

SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and the `async`/`await` syntax.

```javascript
    const res = await request.get(url);
```

If you're using promises, **do not** call `.end()` or `.pipe()`. Any use of `.then()` or `await` disables all other ways of using the request.

Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any SuperAgent method:

```javascript
    const req = request
      .get('http://local')
      .auth('tobi', 'learnboost');
    const res = yield req;
```

Note 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.

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 <https://cdnjs.cloudflare.com/polyfill/>:

```html
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt"></script>
```

## Browser and node versions

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.

If 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.


================================================
FILE: docs/ko_KR/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8" />
    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css"
    />
    <link rel="stylesheet" href="../style.css" />
  </head>
  <body>
    <ul id="menu"></ul>
    <div id="content">
      <h1 id="superagent">SuperAgent</h1>
      <p>
        SuperAgent는 기존의 복잡한 요청 API에 대한 불만에서 출발해 유연성,
        가독성, 그리고 낮은 학습 난이도를 목표로 설계된 경량 Ajax API입니다.
        또한 Node.js 환경에서도 동작합니다!
      </p>
      <pre><code class="language-javascript">     request
       .post(&#39;/api/pet&#39;)
       .send({ name: &#39;Manny&#39;, species: &#39;cat&#39; })
       .set(&#39;X-API-Key&#39;, &#39;foobar&#39;)
       .set(&#39;Accept&#39;, &#39;application/json&#39;)
       .then(res =&gt; {
          alert(&#39;yay got &#39; + JSON.stringify(res.body));
       });
</code></pre>
      <h2 id="test-documentation">테스트 문서</h2>
      <p>
        <a href="../../index.html"><strong>English</strong></a>
      </p>
      <p>
        다음의 <a href="../test.html">테스트 문서</a>는
        <a href="https://mochajs.org/">Mocha&#39;s</a> &quot;doc&quot; 리포터를
        사용해 생성되었으며, 실제 테스트 스위트를 직접 반영합니다. 이 문서는
        추가적인 참고 자료로 활용할 수 있습니다.
      </p>
      <h2 id="request-basics">기본 요청</h2>
      <p>
        요청은 <code>request</code> 객체에서 적절한 메서드를 호출하여 시작되며,
        그 다음 <code>.then()</code> 또는 <code>.end()</code> 혹은
        <a href="#promise-and-generator-support"><code>await</code></a
        >를 사용해 요청을 전송할 수 있습니다. 예를 들어, 간단한
        <strong>GET</strong> 요청은 다음과 같습니다.
      </p>
      <pre><code class="language-javascript">     request
       .get(&#39;/search&#39;)
       .then(res =&gt; {
          // res.body, res.headers, res.status
       })
       .catch(err =&gt; {
          // err.message, err.response
       });
</code></pre>
      <p>HTTP 메서드는 문자열로도 전달할 수 있습니다.</p>
      <pre><code class="language-javascript">    request(&#39;GET&#39;, &#39;/search&#39;).then(success, failure);
</code></pre>
      <p>
        예전 방식의 콜백도 지원되지만, 권장되지는 않습니다.
        <code>.then()</code> 대신 <code>.end()</code>를 호출하여 요청을 전송할
        수 있습니다.
      </p>
      <pre><code class="language-javascript">    request(&#39;GET&#39;, &#39;/search&#39;).end(function(err, res){
      if (res.ok) {}
    });
</code></pre>
      <p>
        절대 URL을 사용할 수 있습니다. 단, 웹 브라우저에서는 서버가
        <a href="#cors">CORS</a>를 구현한 경우에만 절대 URL이 정상적으로
        작동합니다.
      </p>
      <pre><code class="language-javascript">     request
       .get(&#39;https://example.com/search&#39;)
       .then(res =&gt; {

       });
</code></pre>
      <p>
        <strong>Node</strong> 클라이언트는
        <a
          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"
          >유닉스 도메인 소켓</a
        >을 통한 요청을 지원합니다.
      </p>
      <pre><code class="language-javascript">    // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH
    //          Use `%2F` as `/` in SOCKET_PATH
    try {
      const res = await request
        .get(&#39;http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search&#39;);
      // res.body, res.headers, res.status
    } catch(err) {
      // err.message, err.response
    }
</code></pre>
      <p>
        <strong>DELETE</strong>, <strong>HEAD</strong>, <strong>PATCH</strong>,
        <strong>POST</strong>, and <strong>PUT</strong> 요청도 사용할 수 있으며,
        다음 예시에서 메서드 이름만 변경하면 됩니다.
      </p>
      <pre><code class="language-javascript">    request
      .head(&#39;/favicon.ico&#39;)
      .then(res =&gt; {

      });
</code></pre>
      <p>
        <strong>DELETE</strong>는 <code>delete</code>가 예약어였던 구형 IE와의
        호환성을 위해 <code>.del()</code> 메서드로도 호출할 수 있습니다.
      </p>
      <p>
        HTTP 메서드의 기본값은 <strong>GET</strong>이므로, 다음과 같이 작성해도
        유효합니다.
      </p>
      <pre><code class="language-javascript">     request(&#39;/search&#39;, (err, res) =&gt; {

     });
</code></pre>
      <h2 id="using-http/2">HTTP/2 사용하기</h2>
      <p>
        HTTP/1.x 폴백 없이 HTTP/2 프로토콜만 사용하려면
        <code>.http2()</code> 메서드를 호출하여 요청을 전송할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    const request = require(&#39;superagent&#39;);
    const res = await request
      .get(&#39;https://example.com/h2&#39;)
      .http2();
</code></pre>
      <h2 id="setting-header-fields">헤더 필드 설정하기</h2>
      <p>
        헤더 필드 설정은 간단합니다. 필드 이름과 값을
        <code>.set()</code> 메서드에 전달하면 됩니다.
      </p>
      <pre><code class="language-javascript">     request
       .get(&#39;/search&#39;)
       .set(&#39;API-Key&#39;, &#39;foobar&#39;)
       .set(&#39;Accept&#39;, &#39;application/json&#39;)
       .then(callback);
</code></pre>
      <p>여러 개의 헤더 필드를 한 번에 설정하려면 객체를 전달하면 됩니다.</p>
      <pre><code class="language-javascript">     request
       .get(&#39;/search&#39;)
       .set({ &#39;API-Key&#39;: &#39;foobar&#39;, Accept: &#39;application/json&#39; })
       .then(callback);
</code></pre>
      <h2 id="get-requests"><code>GET</code> 요청</h2>
      <p>
        <code>.query()</code> 메서드는 객체를 인자로 받아
        <strong>GET</strong> 요청 시 쿼리 문자열을 자동으로 생성합니다. 예를
        들어 다음 코드는
        <code>/search?query=Manny&amp;range=1..5&amp;order=desc</code> 경로를
        생성합니다.
      </p>
      <pre><code class="language-javascript">     request
       .get(&#39;/search&#39;)
       .query({ query: &#39;Manny&#39; })
       .query({ range: &#39;1..5&#39; })
       .query({ order: &#39;desc&#39; })
       .then(res =&gt; {

       });
</code></pre>
      <p>또는 하나의 객체로 설정할 수 있습니다.</p>
      <pre><code class="language-javascript">    request
      .get(&#39;/search&#39;)
      .query({ query: &#39;Manny&#39;, range: &#39;1..5&#39;, order: &#39;desc&#39; })
      .then(res =&gt; {

      });
</code></pre>
      <p><code>.query()</code> 메서드는 문자열도 받습니다.</p>
      <pre><code class="language-javascript">      request
        .get(&#39;/querystring&#39;)
        .query(&#39;search=Manny&amp;range=1..5&#39;)
        .then(res =&gt; {

        });
</code></pre>
      <p>조인할 수도 있습니다.</p>
      <pre><code class="language-javascript">      request
        .get(&#39;/querystring&#39;)
        .query(&#39;search=Manny&#39;)
        .query(&#39;range=1..5&#39;)
        .then(res =&gt; {

        });
</code></pre>
      <h2 id="head-requests"><code>HEAD</code> 요청하기</h2>
      <p>
        HEAD 요청에서도 <code>.query()</code> 메서드를 사용할 수 있습니다. 예를
        들어 다음 코드는 <code>/users?email=joe@smith.com</code> 경로를
        생성합니다.
      </p>
      <pre><code class="language-javascript">      request
        .head(&#39;/users&#39;)
        .query({ email: &#39;joe@smith.com&#39; })
        .then(res =&gt; {

        });
</code></pre>
      <h2 id="post--put-requests"><code>POST</code> / <code>PUT</code> 요청</h2>
      <p>
        전형적인 JSON <strong>POST</strong> 요청은 Content-Type 헤더를 적절히
        설정하고, 데이터를 JSON 형식으로 전송하는 방식입니다. 예를 들어 다음과
        같은 코드가 이에 해당합니다.
      </p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .set(&#39;Content-Type&#39;, &#39;application/json&#39;)
        .send(&#39;{&quot;name&quot;:&quot;tj&quot;,&quot;pet&quot;:&quot;tobi&quot;}&#39;)
        .then(callback)
        .catch(errorCallback)
</code></pre>
      <p>
        JSON은 가장 일반적으로 사용되므로 기본값으로 설정되어 있습니다. 다음
        예제는 앞선 예제와 동일한 동작을 수행합니다.
      </p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .send({ name: &#39;tj&#39;, pet: &#39;tobi&#39; })
        .then(callback, errorCallback)
</code></pre>
      <p>또는 <code>.send()</code> 여러 번 호출할 수 있습니다.</p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .send({ name: &#39;tj&#39; })
        .send({ pet: &#39;tobi&#39; })
        .then(callback, errorCallback)
</code></pre>
      <p>
        기본적으로 문자열을 전송하면 <code>Content-Type</code>이
        <code>application/x-www-form-urlencoded</code>로 자동 설정됩니다. 여러
        번 <code>.send()</code>를 호출하면 각 문자열이 <code>&amp;</code>로
        연결되어 최종적으로 <code>name=tj&amp;pet=tobi</code>와 같은 결과가
        생성됩니다.
      </p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .send(&#39;name=tj&#39;)
        .send(&#39;pet=tobi&#39;)
        .then(callback, errorCallback);
</code></pre>
      <p>
        SuperAgent는 다양한 형식으로 확장 가능하지만, 기본적으로
        &quot;json&quot;과 &quot;form&quot; 형식을 지원합니다.
        <code>application/x-www-form-urlencoded</code> 형식으로 데이터를
        전송하려면 <code>.type('form')</code>을 호출하면 됩니다. 기본 형식은
        &quot;json&quot;입니다. 다음 요청은 본문에
        &quot;name=tj&amp;pet=tobi&quot;를 포함하여 <strong>POST</strong>됩니다.
      </p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .type(&#39;form&#39;)
        .send({ name: &#39;tj&#39; })
        .send({ pet: &#39;tobi&#39; })
        .then(callback, errorCallback)
</code></pre>
      <p>
        <a href="https://developer.mozilla.org/ko/../Web/API/FormData/FormData"
          ><code>FormData</code></a
        >
        객체를 사용하는 것도 지원됩니다. 다음 예제는 id=&quot;myForm&quot;인
        HTML 폼의 내용을 <strong>POST</strong> 방식으로 전송합니다.
      </p>
      <pre><code class="language-javascript">      request.post(&#39;/user&#39;)
        .send(new FormData(document.getElementById(&#39;myForm&#39;)))
        .then(callback, errorCallback)
</code></pre>
      <h2 id="setting-the-content-type"><code>Content-Type</code> 설정하기</h2>
      <p>
        가장 명확한 해결책은 <code>.set()</code> 메서드를 사용하는 것입니다.
      </p>
      <pre><code class="language-javascript">     request.post(&#39;/user&#39;)
       .set(&#39;Content-Type&#39;, &#39;application/json&#39;)
</code></pre>
      <p>
        간단하게 <code>.type()</code> 메서드를 사용할 수 있으며, 표준화된 MIME
        타입(<code>type/subtype</code>)을 직접 지정하거나 &quot;xml&quot;,
        &quot;json&quot;, &quot;png&quot; 등과 같은 확장자 이름만으로도 설정할
        수 있습니다.
      </p>
      <pre><code class="language-javascript">     request.post(&#39;/user&#39;)
       .type(&#39;application/json&#39;)

     request.post(&#39;/user&#39;)
       .type(&#39;json&#39;)

     request.post(&#39;/user&#39;)
       .type(&#39;png&#39;)
</code></pre>
      <h2 id="serializing-request-body">요청 본문 직렬화하기</h2>
      <p>
        SuperAgent는 기본적으로 JSON과 폼 데이터를 자동으로 직렬화합니다. 또한
        다른 콘텐츠 유형에 대해서도 자동 직렬화를 설정할 수 있습니다.
      </p>
      <pre><code class="language-js">request.serialize[&#39;application/xml&#39;] = function (obj) {
    return &#39;string generated from obj&#39;;
};

// &#39;application/xml&#39; Content-type을 가진 모든 요청은
// 자동으로 직렬화 됩니다.
</code></pre>
      <p>
        사용자 정의 형식으로 페이로드를 전송하려면, 요청 단위로
        <code>.serialize()</code>
        메서드를 사용해 SuperAgent의 기본 직렬화 방식을 교체할 수 있습니다.
      </p>
      <pre><code class="language-js">request
    .post(&#39;/user&#39;)
    .send({foo: &#39;bar&#39;})
    .serialize(obj =&gt; {
        return &#39;string generated from obj&#39;;
    });
</code></pre>
      <h2 id="retrying-requests">요청 재시도하기</h2>
      <p>
        <code>.retry()</code> 메서드를 사용하면, 일시적인 오류나 불안정한 인터넷
        연결로 인해 요청이 실패한 경우 SuperAgent가 자동으로 재시도합니다.
      </p>
      <p>
        이 메서드는 두 개의 선택적 인자를 받습니다. 재시도 횟수(기본값은 1)와
        콜백 함수입니다. 각 재시도 전에 <code>callback(err, res)</code>를
        호출합니다. 콜백 함수는 요청을 재시도할지 여부를 결정하기 위해
        <code>true</code> 또는 <code>false</code>를 반환할 수 있습니다. 단, 최대
        재시도 횟수는 항상 적용됩니다.
      </p>
      <pre><code class="language-javascript">     request
       .get(&#39;https://example.com/search&#39;)
       .retry(2) // 혹은
       .retry(2, callback)
       .then(finished);
       .catch(failed);
</code></pre>
      <p>
        멱등한 요청인 경우에만 <code>.retry()</code> 메서드를 사용하세요. 예를
        들어, 동일한 요청이 서버에 여러 번 도달하더라도 중복 구매와 같은
        바람직하지 않은 부작용이 발생하지 않아야 합니다.
      </p>
      <p>
        모든 요청 메서드는 기본적으로 재시도 대상에 포함됩니다. 따라서 POST
        요청을 재시도하지 않도록 하려면, 사용자 정의 재시도 콜백을 전달해야
        합니다.
      </p>
      <p>기본적으로 다음과 같은 상태 코드는 자동으로 재시도됩니다.</p>
      <ul>
        <li><code>408</code></li>
        <li><code>413</code></li>
        <li><code>429</code></li>
        <li><code>500</code></li>
        <li><code>502</code></li>
        <li><code>503</code></li>
        <li><code>504</code></li>
        <li><code>521</code></li>
        <li><code>522</code></li>
        <li><code>524</code></li>
      </ul>
      <p>기본적으로 다음과 같은 오류 코드가 자동으로 재시도됩니다.</p>
      <ul>
        <li><code>&#39;ETIMEDOUT&#39;</code></li>
        <li><code>&#39;ECONNRESET&#39;</code></li>
        <li><code>&#39;EADDRINUSE&#39;</code></li>
        <li><code>&#39;ECONNREFUSED&#39;</code></li>
        <li><code>&#39;EPIPE&#39;</code></li>
        <li><code>&#39;ENOTFOUND&#39;</code></li>
        <li><code>&#39;ENETUNREACH&#39;</code></li>
        <li><code>&#39;EAI_AGAIN&#39;</code></li>
      </ul>
      <h2 id="setting-accept">Accept 설정하기</h2>
      <p>
        <code>.type()</code> 메서드와 유사하게, <code>.accept()</code> 메서드를
        사용하면 <code>Accept</code> 헤더를 간편하게 설정할 수 있습니다. 이
        메서드는 <code>request.types</code>를 참조하며,
        <code>type/subtype</code> 형식의 MIME 타입 전체 이름이나
        &quot;xml&quot;, &quot;json&quot;, &quot;png&quot; 등의 확장자 형태로도
        지정할 수 있어 편리합니다.
      </p>
      <pre><code class="language-javascript">     request.get(&#39;/user&#39;)
       .accept(&#39;application/json&#39;)

     request.get(&#39;/user&#39;)
       .accept(&#39;json&#39;)

     request.post(&#39;/user&#39;)
       .accept(&#39;png&#39;)
</code></pre>
      <h3 id="facebook-and-accept-json">Facebook과 Accept JSON</h3>
      <p>
        Facebook API를 호출할 때는 반드시 요청 헤더에
        <code>Accept: application/json</code>을 포함해야 합니다. 그렇지 않으면
        Facebook은 <code>Content-Type: text/javascript; charset=UTF-8</code>으로
        응답하게 되며, SuperAgent는 이 형식을 파싱하지 못해
        <code>res.body</code>가 undefined가 됩니다.
        <code>req.accept(&#39;json&#39;)</code> 또는
        <code>req.set(&#39;Accept&#39;, &#39;application/json&#39;)</code>을
        사용할 수 있습니다. 자세한 사항은
        <a href="https://github.com/ladjs/superagent/issues/1078">issue 1078</a>
        에서 확인해보세요.
      </p>
      <h2 id="query-strings">쿼리 문자열</h2>
      <p>
        <code>req.query(obj)</code>는 쿼리 문자열을 구성하는 데 사용되는
        메서드입니다. 예를 들어 <strong>POST</strong> 요청에서
        <code>?format=json&amp;dest=/login</code>과 같은 쿼리 문자열을 추가할 수
        있습니다.
      </p>
      <pre><code class="language-javascript">    request
      .post(&#39;/&#39;)
      .query({ format: &#39;json&#39; })
      .query({ dest: &#39;/login&#39; })
      .send({ post: &#39;data&#39;, here: &#39;wahoo&#39; })
      .then(callback);
</code></pre>
      <p>
        기본적으로 쿼리 문자열은 특정한 순서로 조립되지 않습니다. ASCII 순으로
        정렬된 쿼리 문자열을 사용하려면
        <code>req.sortQuery()</code>를 호출하면 됩니다. 또한
        <code>req.sortQuery(myComparisonFn)</code>을 통해 사용자 정의 정렬 비교
        함수를 전달할 수도 있습니다. 비교 함수는 두 개의 인자를 받아 음수, 0
        또는 양수를 반환해야 합니다.
      </p>
      <pre><code class="language-js"> // 기본 정렬 방식
 request.get(&#39;/user&#39;)
   .query(&#39;name=Nick&#39;)
   .query(&#39;search=Manny&#39;)
   .sortQuery()
   .then(callback)

 // 사용자 정의 정렬 함수
 request.get(&#39;/user&#39;)
   .query(&#39;name=Nick&#39;)
   .query(&#39;search=Manny&#39;)
   .sortQuery((a, b) =&gt; a.length - b.length)
   .then(callback)
</code></pre>
      <h2 id="tls-options">TLS 옵션</h2>
      <p>
        Node.js에서 SuperAgent는 HTTPS 요청을 구성할 수 있는 다양한 메서드를
        지원합니다.
      </p>
      <ul>
        <li><code>.ca()</code>: 신뢰할 CA 인증서를 설정합니다.</li>
        <li><code>.cert()</code>: 클라이언트 인증서 체인을 설정합니다.</li>
        <li><code>.key()</code>: 클라이언트의 개인 키를 설정합니다.</li>
        <li>
          <code>.pfx()</code>: PKCS12 형식의 PFX 파일을 사용하여 클라이언트의
          개인 키와 인증서 체인을 설정합니다.
        </li>
        <li>
          <code>.disableTLSCerts()</code>: 만료되었거나 유효하지 않은 TLS
          인증서를 거부하지 않도록 설정합니다. 내부적으로
          <code>rejectUnauthorized=true</code>가 설정되며, 중간자 공격(MITM)에
          노출될 수 있으므로 주의가 필요합니다.
        </li>
      </ul>
      <p>
        더 자세한 내용은 Node.js
        <a
          href="https://nodejs.org/api/https.html#https_https_request_options_callback"
          >https.request 문서</a
        >에서 확인할 수 있습니다.
      </p>
      <pre><code class="language-js">var key = fs.readFileSync(&#39;key.pem&#39;),
    cert = fs.readFileSync(&#39;cert.pem&#39;);

request
  .post(&#39;/client-auth&#39;)
  .key(key)
  .cert(cert)
  .then(callback);
</code></pre>
      <pre><code class="language-js">var ca = fs.readFileSync(&#39;ca.cert.pem&#39;);

request
  .post(&#39;https://localhost/private-ca-server&#39;)
  .ca(ca)
  .then(res =&gt; {});
</code></pre>
      <h2 id="parsing-response-bodies">응답 본문 파싱하기</h2>
      <p>
        SuperAgent는 응답 본문 데이터를 자동으로 파싱해줍니다. 현재
        <code>application/x-www-form-urlencoded</code>,
        <code>application/json</code>, <code>multipart/form-data</code>을
        지원합니다. 이외의 응답 본문 데이터에 대해서도 자동 파싱을 설정할 수
        있습니다.
      </p>
      <pre><code class="language-js">// 브라우저
request.parse[&#39;application/xml&#39;] = function (str) {
    return {&#39;object&#39;: &#39;parsed from str&#39;};
};

// node
request.parse[&#39;application/xml&#39;] = function (res, cb) {
    //parse response text and set res.body here

    cb(null, res);
};

// 앞으로 &#39;application/xml&#39; 유형의 반응은
// 자동으로 파싱됩니다
</code></pre>
      <p>
        <code>.buffer(true).parse(fn)</code> 메서드를 사용하면 내장된 파서보다
        우선적으로 적용되는 사용자 정의 파서를 설정할 수 있습니다.
        <code>.buffer(false)</code>로 응답 버퍼링이 비활성화되어 있다면,
        <code>response</code> 이벤트는 본문 파싱이 완료되기 전에 발생하므로
        <code>response.body</code>를 사용할 수 없습니다.
      </p>
      <h3 id="json--urlencoded">JSON / Urlencoded</h3>
      <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; 값을 갖게
        됩니다. 마찬가지로 x-www-form-urlencoded 형식의
        &quot;user[name]=tobi&quot;도 동일한 결과를 제공합니다. 단, 중첩은 한
        단계까지만 지원되므로 더 복잡한 구조의 데이터를 다루려면 JSON 형식을
        사용하는 것이 좋습니다.
      </p>
      <p>
        배열은 key를 반복해서 전달하는 방식으로 전송됩니다.
        <code>.send({color: [&#39;red&#39;,&#39;blue&#39;]})</code>는
        <code>color=red&amp;color=blue</code>로 변환되어 전송됩니다. 배열의
        key에 <code>[]</code>를 포함시키고 싶다면 SuperAgent는 이를 자동으로
        처리하지 않으므로, 직접 <code>color[]</code>와 같이 key 이름에 대괄호를
        추가해야 합니다.
      </p>
      <h3 id="multipart">다중 파트</h3>
      <p>
        Node 클라이언트는
        <a href="https://github.com/felixge/node-formidable">Formidable</a>
        모듈을 통해 <em>multipart/form-data</em>를 지원합니다. 다중 파트 응답을
        파싱할 때 <code>res.files</code> 객체를 사용할 수 있으며, 이 객체에는
        업로드된 파일에 대한 정보가 포함됩니다. 예를 들어, 다음과 같은 multipart
        본문을 포함한 응답을 가정해볼 수 있습니다.
      </p>
      <pre><code>--whoop
Content-Disposition: attachment; name=&quot;image&quot;; filename=&quot;tobi.png&quot;
Content-Type: image/png

... data here ...
--whoop
Content-Disposition: form-data; name=&quot;name&quot;
Content-Type: text/plain

Tobi
--whoop--
</code></pre>
      <p>
        <code>res.body.name</code>은 &quot;Tobi&quot; 값을 가지고 있으며,
        <code>res.files.image</code>는 디스크 경로, 파일 이름 및 기타 속성을
        포함한 <code>File</code> 객체입니다.
      </p>
      <h3 id="binary">바이너리</h3>
      <p>
        브라우저에서는 바이너리 응답 본문을 처리하기 위해
        <code>.responseType(&#39;blob&#39;)</code>을 사용할 수 있습니다. 이
        API는 Node.js 환경에서는 필요하지 않습니다. 이 메서드에서 지원되는 인자
        값은 다음과 같습니다.
      </p>
      <ul>
        <li>
          <code>&#39;blob&#39;</code>는 XMLHttpRequest의
          <code>responseType</code> 속성에 그대로 전달됩니다.
        </li>
        <li>
          <code>&#39;arraybuffer&#39;</code>도 마찬가지로
          <code>responseType</code> 속성에 전달됩니다.
        </li>
      </ul>
      <pre><code class="language-js">req.get(&#39;/binary.data&#39;)
  .responseType(&#39;blob&#39;)
  .then(res =&gt; {
    // 여기서 res.body는 브라우저 기본 Blob 타입입니다.
  });
</code></pre>
      <p>
        더 자세한 내용은 Mozilla Developer Network의
        <a
          href="https://developer.mozilla.org/en-US/../Web/API/XMLHttpRequest/responseType"
          >XMLHttpRequest.responseType 문서</a
        >에서 확인할 수 있습니다.
      </p>
      <h2 id="response-properties">응답 속성</h2>
      <p>
        <code>Response</code> 객체에는 응답 텍스트, 파싱된 응답 본문, 헤더 필드,
        상태 플래그 등 다양한 유용한 플래그와 속성이 설정되어 있습니다.
      </p>
      <h3 id="response-text">응답 문자</h3>
      <p>
        <code>res.text</code> 속성에는 파싱되지 않은 응답 본문 문자열이
        포함됩니다. 이 속성은 클라이언트 API에서는 항상 존재하며, Node
        환경에서는 MIME 타입이 &quot;text/<em>&quot;, &quot;</em>/json&quot;,
        또는 &quot;x-www-form-urlencoded&quot;와 일치할 경우에만 기본적으로
        제공됩니다. 이러한 제한은 대용량 multipart 파일이나 이미지 등의 본문을
        텍스트로 버퍼링하는 것이 매우 비효율적이기 때문에 메모리를 절약하기 위한
        목적입니다. 응답을 강제로 버퍼링하려면 &quot;응답 버퍼링&quot; 섹션을
        참조하세요.
      </p>
      <h3 id="response-body">응답 본문</h3>
      <p>
        SuperAgent는 요청 데이터를 자동으로 직렬화할 뿐만 아니라, 자동으로
        파싱할 수도 있습니다. Content-Type에 대해 파서가 정의되어 있는 경우,
        해당 타입에 맞게 응답이 파싱되며 기본적으로
        &quot;application/json&quot;과
        &quot;application/x-www-form-urlencoded&quot; 형식이 포함됩니다. 파싱된
        객체는 <code>res.body</code>를 통해 접근할 수 있습니다.
      </p>
      <h3 id="response-header-fields">응답 헤더 필드</h3>
      <p>
        <code>res.header</code>는 파싱된 응답 헤더 필드를 담은 객체로, Node.js와
        마찬가지로 필드 이름을 소문자로 변환하여 저장합니다. 예를 들어,
        <code>res.header[&#39;content-length&#39;]</code>와 같이 접근할 수
        있습니다.
      </p>
      <h3 id="response-content-type">응답 콘텐츠 타입</h3>
      <p>
        Content-Type 응답 헤더는 특별하게 처리되어 <code>res.type</code> 속성은
        charset 정보를 제외한 콘텐츠 타입만을 제공합니다. 예를 들어
        Content-Type이 &quot;text/html; charset=utf8&quot;인 경우,
        <code>res.type</code>은 &quot;text/html&quot;을 반환하고,
        <code>res.charset</code> 속성에는 &quot;utf8&quot;이 포함됩니다.
      </p>
      <h3 id="response-status">응답 상태</h3>
      <p>
        응답 상태 플래그는 요청이 성공했는지 여부를 비롯한 다양한 유용한 정보를
        판단하는 데 도움을 줍니다. 이를 통해 SuperAgent는 RESTful 웹 서비스와
        효과적으로 상호작용할 수 있습니다. 현재 정의된 주요 플래그는 다음과
        같습니다.
      </p>
      <pre><code class="language-javascript">     var type = status / 100 | 0;

     // 상태 / 클래스
     res.status = status;
     res.statusType = type;

     // 기본
     res.info = 1 == type;
     res.ok = 2 == type;
     res.clientError = 4 == type;
     res.serverError = 5 == type;
     res.error = 4 == type || 5 == type;

     // 편의 기능
     res.accepted = 202 == status;
     res.noContent = 204 == status || 1223 == status;
     res.badRequest = 400 == status;
     res.unauthorized = 401 == status;
     res.notAcceptable = 406 == status;
     res.notFound = 404 == status;
     res.forbidden = 403 == status;
</code></pre>
      <h2 id="aborting-requests">요청 중단하기</h2>
      <p>
        요청을 중단하려면 <code>req.abort()</code> 메서드를 호출하기만 하면
        됩니다.
      </p>
      <h2 id="timeouts">타임아웃</h2>
      <p>
        때때로 네트워크나 서버가 요청을 수신한 후 응답 없이 멈춰버리는 경우가
        있습니다. 이러한 무한 대기를 방지하려면 타임아웃을 설정해야 합니다.
      </p>
      <ul>
        <li>
          <p>
            <code>req.timeout({deadline:ms})</code> 또는
            <code>req.timeout(ms)</code>는 업로드, 리다이렉트, 서버 처리 시간을
            포함한 전체 요청이 완료되어야 하는 최종 시간 제한을 설정합니다.
            <code>ms</code>는 0보다 큰 밀리초 단위의 숫자이며, 제한 시간 내에
            응답이 완료되지 않으면 요청은 중단됩니다.
          </p>
        </li>
        <li>
          <p>
            <code>req.timeout({response:ms})</code>는 서버로부터 첫 번째
            바이트가 도착할 때까지의 최대 대기 시간을 설정합니다. 전체 다운로드
            소요 시간은 제한하지 않습니다. 응답 타임아웃은 DNS 조회, TCP/IP 및
            TLS 연결, 요청 데이터 업로드 시간을 포함하므로, 서버의 실제 응답
            시간보다 몇 초 더 길게 설정하는 것이 좋습니다.
          </p>
        </li>
      </ul>
      <p>
        <code>deadline</code>과 <code>response</code> 타임아웃은 함께 사용하는
        것이 좋습니다. 짧은 응답 타임아웃은 응답하지 않는 네트워크를 빠르게
        감지하는 데 유용하고, 긴 데드라인은 느리지만 안정적인 네트워크 환경에서
        다운로드를 완료할 수 있도록 여유 시간을 제공합니다. 두 타이머 모두
        첨부된 파일 업로드에 허용되는 시간을 제한합니다. 파일을 업로드하는
        경우에는 충분히 긴 타임아웃을 설정하는 것이 좋습니다.
      </p>
      <pre><code class="language-javascript">    request
      .get(&#39;/big-file?network=slow&#39;)
      .timeout({
        response: 5000,  // 서버가 데이터를 보내기 시작할 때까지 최대 5초간 기다립니다.
        deadline: 60000, // 파일 전체를 로드하는 데 최대 1분까지 허용합니다.
      })
      .then(res =&gt; {
          /* 제시간 응답 수신 */
        }, err =&gt; {
          if (err.timeout) { /* 시간 초과! */ } else { /* 그 외 오류 */ }
      });
</code></pre>
      <p>타임아웃 오류에는 <code>.timeout</code> 속성이 포함되어 있습니다.</p>
      <h2 id="authentication">인증</h2>
      <p>
        Node와 브라우저 환경에서 <code>.auth()</code> 메서드를 사용하여 인증을
        수행할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    request
      .get(&#39;http://local&#39;)
      .auth(&#39;tobi&#39;, &#39;learnboost&#39;)
      .then(callback);
</code></pre>
      <p>
        <em>Node</em> 클라이언트에서는 기본 인증을 URL 내에
        &quot;user:pass&quot; 형식으로 포함시킬 수 있습니다.
      </p>
      <pre><code class="language-javascript">    request.get(&#39;http://tobi:learnboost@local&#39;).then(callback);
</code></pre>
      <p>
        기본적으로 <code>Basic</code> 인증만 사용됩니다. 브라우저에서는
        <code>{type:&#39;auto&#39;}</code>를 추가하면 Digest, NTLM 등 브라우저에
        내장된 모든 인증 방식을 사용할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    request.auth(&#39;digest&#39;, &#39;secret&#39;, {type:&#39;auto&#39;})
</code></pre>
      <p>
        <code>auth</code> 메서드는 토큰 기반 인증을 위한 <code>type</code>의
        <code>bearer</code> 옵션도 지원합니다.
      </p>
      <pre><code class="language-javascript">    request.auth(&#39;my_token&#39;, { type: &#39;bearer&#39; })
</code></pre>
      <h2 id="following-redirects">다음 리다이렉션 따라가기</h2>
      <p>
        기본적으로 최대 5번까지 리다이렉션이 자동으로 따라가며, 필요에 따라
        <code>res.redirects(n)</code> 메서드를 사용하여 이 횟수를 지정할 수
        있습니다.
      </p>
      <pre><code class="language-javascript">    const response = await request.get(&#39;/some.png&#39;).redirects(2);
</code></pre>
      <p>
        리다이렉션 횟수가 제한을 초과하면 오류로 간주됩니다. 이를 성공적인
        응답으로 처리하려면
        <code>.ok(res =&gt; res.status &lt; 400)</code> 메서드를 사용하세요.
      </p>
      <h2 id="agents-for-global-state">전역 상태를 위한 에이전트</h2>
      <h3 id="saving-cookies">쿠키 저장하기</h3>
      <p>
        Node에서 SuperAgent는 기본적으로 쿠키를 저장하지 않습니다. 하지만
        <code>.agent()</code> 메서드를 사용하면 쿠키를 저장하는 SuperAgent
        인스턴스를 생성할 수 있습니다. 각 인스턴스는 독립적인 쿠키 저장소를
        가지고 있습니다.
      </p>
      <pre><code class="language-javascript">    const agent = request.agent();
    agent
      .post(&#39;/login&#39;)
      .then(() =&gt; {
        return agent.get(&#39;/cookied-page&#39;);
      });
</code></pre>
      <p>
        브라우저에서는 쿠키가 자동으로 관리되므로
        <code>.agent()</code>를 사용해도 쿠키가 분리되지는 않습니다.
      </p>
      <h3 id="default-options-for-multiple-requests">
        다중 요청을 위한 기본 옵션
      </h3>
      <p>
        에이전트에서 호출된 일반 요청 메서드는 해당 에이전트가 처리하는 모든
        요청에 대해 기본값으로 적용됩니다.
      </p>
      <pre><code class="language-javascript">    const agent = request.agent()
      .use(plugin)
      .auth(shared);

    await agent.get(&#39;/with-plugin-and-auth&#39;);
    await agent.get(&#39;/also-with-plugin-and-auth&#39;);
</code></pre>
      <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>
      <h2 id="piping-data">데이터 전달 방식</h2>
      <p>
        <code>.pipe()</code>는 <code>.end()</code> 또는
        <code>.then()</code> 메서드 <strong>대신</strong> 사용되며, Node
        클라이언트는 요청과 응답 간에 데이터를 주고받도록 파이프 처리할 수
        있습니다.
      </p>
      <p>
        예를 들어, 파일의 콘텐츠를 요청 본문으로 전달하는 경우는 다음과
        같습니다.
      </p>
      <pre><code class="language-javascript">    const request = require(&#39;superagent&#39;);
    const fs = require(&#39;fs&#39;);

    const stream = fs.createReadStream(&#39;path/to/my.json&#39;);
    const req = request.post(&#39;/somewhere&#39;);
    req.type(&#39;json&#39;);
    stream.pipe(req);
</code></pre>
      <p>
        요청에 데이터를 파이프할 경우, SuperAgent는 해당 데이터를
        <a href="https://en.wikipedia.org/wiki/Chunked_transfer_encoding"
          >청크 전송 인코딩</a
        >
        방식으로 전송합니다. 이 방식은 Python WSGI 서버 등 모든 서버에서
        지원되지는 않습니다.
      </p>
      <p>응답을 파일로 저장하려면 다음과 같이 파이프 처리할 수 있습니다.</p>
      <pre><code class="language-javascript">    const stream = fs.createWriteStream(&#39;path/to/my.json&#39;);
    const req = request.get(&#39;/some.json&#39;);
    req.pipe(stream);
</code></pre>
      <p>
        파이프와 콜백 또는 프로미스는 <strong>함께 사용할 수 없으며</strong>,
        <code>.end()</code>나 <code>Response</code> 객체의 결과를 파이프
        처리해서는 안 됩니다.
      </p>
      <pre><code class="language-javascript">    // 이러한 방식으로 하지 마세요.
    const stream = getAWritableStream();
    const req = request
      .get(&#39;/some.json&#39;)
      // 나쁨: 이 방식은 스트림에 올바르지 않은 데이터를 전달하며 예기치 못한 방식으로 실패할 수 있습니다.
      .end((err, this_does_not_work) =&gt; this_does_not_work.pipe(stream))
    const req = request
      .get(&#39;/some.json&#39;)
      .end()
      // 나쁨: 이 방식도 지원되지 않으며, .pipe는 자동으로 .end를 호출합니다.
      .pipe(nope_its_too_late);
</code></pre>
      <p>
        SuperAgent의
        <a href="https://github.com/ladjs/superagent/issues/1188">향후 버전</a
        >에서는 <code>pipe()</code>를 부적절하게 호출하면 실패하게 됩니다.
      </p>
      <h2 id="multipart-requests">다중 부분 요청</h2>
      <p>
        <code>.attach()</code>와 <code>.field()</code> 메서드를 제공하는
        SuperAgent는 다중 부분 요청을 구성하는 데에도 매우 유용합니다.
      </p>
      <p>
        <code>.field()</code> 또는 <code>.attach()</code>를 사용할 경우
        <code>.send()</code>는 사용할 수 없으며,
        <code>Content-Type</code> 헤더를 직접 설정해서는 안 됩니다. 올바른
        타입은 자동으로 지정됩니다.
      </p>
      <h3 id="attaching-files">파일 첨부하기</h3>
      <p>
        <code>.attach(name, [file], [options])</code>를 사용하여 파일을 전송할
        수 있습니다. 여러 파일을 첨부하려면 <code>.attach</code>를 반복 호출하면
        됩니다. 인자는 다음과 같습니다.
      </p>
      <ul>
        <li><code>name</code> — 폼 이름 필드.</li>
        <li>
          <code>file</code> — 파일 경로의 문자열 또는 <code>Blob</code>/<code
            >Buffer</code
          >
          객체.
        </li>
        <li>
          <code>options</code> — (선택) 사용자 정의 파일 이름의 문자열 또는
          <code>{filename: string}</code> 형식의 객체. 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>
      </ul>
      <br />

      <pre><code class="language-javascript">    request
      .post(&#39;/upload&#39;)
      .attach(&#39;image1&#39;, &#39;path/to/felix.jpeg&#39;)
      .attach(&#39;image2&#39;, imageBuffer, &#39;luna.jpeg&#39;)
      .field(&#39;caption&#39;, &#39;My cats&#39;)
      .then(callback);
</code></pre>
      <h3 id="field-values">필드 값</h3>
      <p>
        <code>.field(name, value)</code> 및 <code>.field({name: value})</code>를
        사용해 HTML 폼 필드처럼 값을 설정할 수 있습니다. 예를 들어 이름과 이메일
        정보를 함께 여러 이미지를 업로드하려면, 요청은 다음과 같이 구성될 수
        있습니다.
      </p>
      <pre><code class="language-javascript">     request
       .post(&#39;/upload&#39;)
       .field(&#39;user[name]&#39;, &#39;Tobi&#39;)
       .field(&#39;user[email]&#39;, &#39;tobi@learnboost.com&#39;)
       .field(&#39;friends[]&#39;, [&#39;loki&#39;, &#39;jane&#39;])
       .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)
       .then(callback);
</code></pre>
      <h2 id="compression">압축</h2>
      <p>
        node 클라이언트는 압축된 응답을 지원하며, 아무 것도 하지 않아도 됩니다!
        그냥 작동합니다.
      </p>
      <h2 id="buffering-responses">응답 버퍼링</h2>
      <p>
        <code>.req.buffer()</code>를 호출하면 응답 본문을
        <code>res.text</code>로 강제 버퍼링할 수 있습니다.
        &quot;text/plain&quot;, &quot;text/html&quot; 등 텍스트 응답의 기본
        버퍼링을 취소하려면 <code>req.buffer(false)</code>를 호출하세요.
      </p>
      <p>
        <code>res.buffered</code> 플래그가 제공되면, 이를 활용하여 동일한 콜백
        함수에서 버퍼링된 응답과 버퍼링되지 않은 응답을 모두 처리할 수 있습니다.
      </p>
      <h2 id="cors">CORS</h2>
      <p>
        보안상의 이유로 브라우저는 서버가 CORS 헤더를 통해 명시적으로 허용하지
        않으면 교차 출처 요청(cross-origin requests)을 차단합니다. 브라우저는
        또한 서버가 어떤 HTTP 헤더와 메서드를 허용하는지 확인하기 위해 추가적인
        <strong>OPTIONS</strong> 요청을 전송합니다.
        <a
          href="https://developer.mozilla.org/ko/../Web/HTTP/Access_control_CORS"
          >CORS에 대해 더 알아보기</a
        >.
      </p>
      <p>
        <code>.withCredentials()</code> 메서드는 origin(출처)에서 쿠키를 전송할
        수 있도록 활성화합니다. 단, 이 기능은
        <code>Access-Control-Allow-Origin</code> 값이
        와일드카드(&quot;*&quot;)가 <em>아니어야</em> 하며,
        <code>Access-Control-Allow-Credentials</code> 값이 &quot;true&quot;일
        경우에만 작동합니다.
      </p>
      <pre><code class="language-javascript">    request
      .get(&#39;https://api.example.com:4001/&#39;)
      .withCredentials()
      .then(res =&gt; {
        assert.equal(200, res.status);
        assert.equal(&#39;tobi&#39;, res.text);
      })
</code></pre>
      <h2 id="error-handling">오류 처리하기</h2>
      <p>
        콜백 함수는 항상 두 개의 인자를 전달합니다. 오류와 응답입니다. 오류가
        발생하지 않으면, 첫 번째 인자는 null 입니다.
      </p>
      <pre><code class="language-javascript">    request
     .post(&#39;/upload&#39;)
     .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)
     .then(res =&gt; {

     });
</code></pre>
      <p>
        "error" 이벤트도 발생하며, 이를 통해 오류를 감지하고 처리할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    request
      .post(&#39;/upload&#39;)
      .attach(&#39;image&#39;, &#39;path/to/tobi.png&#39;)
      .on(&#39;error&#39;, handle)
      .then(res =&gt; {

      });
</code></pre>
      <p>
        <strong
          >SuperAgent는 기본적으로 4xx 및 5xx 응답(그리고 처리되지 않은 3xx
          응답도 포함)을 오류</strong
        >로 간주합니다. 예를 들어 <code>304 Not Modified</code>,
        <code>403 Forbidden</code> 또는
        <code>500 Internal Server Error</code> 같은 응답을 받으면 해당 상태
        정보는 <code>err.status</code>를 통해 확인할 수 있습니다. 이러한
        응답으로부터 발생한 오류에는 &quot;<a href="#response-properties"
          >응답 요소</a
        >&quot;에서 언급한 모든 속성을 포함한 <code>err.response</code> 필드도
        포함됩니다. 이 라이브러리는 일반적으로 성공 응답만을 원하고, HTTP 오류
        상태 코드를 오류로 처리하는 경우를 대비하여 이러한 방식으로 동작합니다.
        하지만 특정 오류 조건에 대해서는 사용자 정의 로직을 허용하도록 설계되어
        있습니다.
      </p>
      <p>
        네트워크 실패, 시간초과, 응답 없는 오류는 <code>err.status</code> 또는
        <code>err.response</code> 필드를 포함하지 않습니다.
      </p>
      <p>
        404 또는 HTTP 오류 응답을 처리하고 싶다면,
        <code>error.status</code> 요소를 사용할 수 있습니다. HTTP 오류(4xx 또는
        5xx 응답)가 발생했을 때 <code>res.error</code> 요소는
        <code>Error</code> 객체이고 이는 다음과 같이 에러 확인을 수행할 수
        있습니다.
      </p>
      <pre><code class="language-javascript">    if (err &amp;&amp; err.status === 404) {
      alert(&#39;oh no &#39; + res.body.message);
    }
    else if (err) {
      // 그 외 다른 모든 오류 유형은 일반적으로 처리합니다
    }
</code></pre>
      <p>
        대안으로, <code>.ok(callback)</code> 메서드를 사용하여 응답이 오류인지
        아닌지 결정할 수 있습니다. <code>ok</code> 콜백은 응답을 받고 응답이
        성공으로 해석되면 <code>true</code>를 반환합니다.
      </p>
      <pre><code class="language-javascript">    request.get(&#39;/404&#39;)
      .ok(res =&gt; res.status &lt; 500)
      .then(response =&gt; {
        // 404 페이지를 성공적인 응답으로 처리합니다
      })
</code></pre>
      <h2 id="progress-tracking">진행과정 추적하기</h2>
      <p>
        SuperAgent는 업로드와 큰 파일 다운로드에서
        <code>progress</code> 이벤트를 동작시킵니다.
      </p>
      <pre><code class="language-javascript">    request.post(url)
      .attach(&#39;field_name&#39;, file)
      .on(&#39;progress&#39;, event =&gt; {
        /* the event is:
        {
          direction: &quot;upload&quot; or &quot;download&quot;
          percent: 0 to 100 // 0에서 100까지 (파일 크기를 알 수 없는 경우 생략될 수 있습니다)
          total: // 전체 파일 크기 (생략될 수 있습니다)
          loaded: // 현재까지 다운로드되거나 업로드된 바이트 수
        } */
      })
      .then()
</code></pre>
      <h2 id="testing-on-localhost">로컬 호스트에서 테스트하기</h2>
      <h3 id="forcing-specific-connection-ip-address">
        특정 IP 주소 연결 설정하기
      </h3>
      <p>
        Node.js에서는 DNS를 무시하고 <code>.connect()</code> 메서드를 사용하여
        모든 요청을 특정 IP 주소로 직접 연결할 수 있습니다. 예를 들어, 이 요청은
        <code>example.com</code> 대신 로컬호스트로 전달됩니다.
      </p>
      <pre><code class="language-javascript">    const res = await request.get(&quot;http://example.com&quot;).connect(&quot;127.0.0.1&quot;);
</code></pre>
      <p>
        요청은 리다이렉트 되어, 여러 호스트명과 IP를 특정지을 수 있으며 특별한
        <code>*</code>를 대체로 설정할 수 있습니다. (다른 와일드 카드는 지원되지
        않습니다). 요청은 원본 값을 가지며 본인의 <code>Host</code> 헤더를
        유지합니다. <code>.connect(undefined)</code>는 이러한 기능을 끕니다.
      </p>
      <pre><code class="language-javascript">    const res = await request.get(&quot;http://redir.example.com:555&quot;)
      .connect({
        &quot;redir.example.com&quot;: &quot;127.0.0.1&quot;, // redir.example.com:555는 127.0.0.1:555를 사용합니다.
        &quot;www.example.com&quot;: false, // 이 항목은 재정의하지 마세요. 일반적인 DNS 설정을 사용합니다.
        &quot;mapped.example.com&quot;: { host: &quot;127.0.0.1&quot;, port: 8080}, // mapped.example.com의 모든 포트는 127.0.0.1:8080으로 매핑됩니다.
        &quot;*&quot;: &quot;proxy.example.com&quot;, // 나머지 모든 요청은 이 호스트로 전달됩니다
      });
</code></pre>
      <h3 id="ignoring-brokeninsecure-https-on-localhost">
        로컬 호스트에서 깨지거나 보안되지 않은 HTTPS 무시하기
      </h3>
      <p>
        Node.js에서 HTTPS 설정이 잘못되었거나 보안성이 떨어지는 경우(예: 자체
        서명된 인증서를 사용하면서
        <code>.ca()</code>를 지정하지 않은 경우),
        <code>.trustLocalhost()</code>를 호출하면 <code>localhost</code>로의
        요청을 허용할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    const res = await request.get(&quot;https://localhost&quot;).trustLocalhost()
</code></pre>
      <p>
        <code>.connect(&quot;127.0.0.1&quot;)</code>와 함께 사용하면 HTTPS
        요청을 어떤 도메인에서든 <code>localhost</code>로 강제로 리다이렉트할 수
        있습니다.
      </p>
      <p>
        <code>localhost</code>는 신뢰되지 않은 네트워크에 노출되지 않는 루프백
        인터페이스이기 때문에, 깨진 HTTPS를 무시하는 것이 일반적으로 안전합니다.
        <code>localhost</code>를 신뢰하도록 설정하는 것이 향후 기본값이 될 수
        있습니다. <code>127.0.0.1</code>&#39;의 진위 여부를 강제로 검사하려면
        <code>.trustLocalhost(false)</code>를 사용하세요.
      </p>
      <p>
        다른 IP 주소로 요청을 보낼 때 HTTPS 보안을 비활성화하는 기능은
        의도적으로 지원하지 않습니다. 이러한 옵션은 HTTPS 문제를 빠르게
        &quot;해결&quot;하려는 방식으로 오용되는 경우가 많기 때문입니다.
        <a href="https://certbot.eff.org">Let&#39;s Encrypt</a>를 통해 무료
        HTTPS 인증서를 발급하거나, <code>.ca(ca_public_pem)</code>을 사용해 자체
        서명된 인증서를 신뢰할 수 있도록 직접 CA를 설정할 수 있습니다.
      </p>
      <h2 id="promise-and-generator-support">Promise 및 Generator 지원</h2>
      <p>
        SuperAgent의 요청은 &quot;thenable&quot; 객체이며, JavaScript의 Promise
        및 <code>async</code>/<code>await</code>
        문법과 호환됩니다.
      </p>
      <pre><code class="language-javascript">    const res = await request.get(url);
</code></pre>
      <p>
        Promise를 사용할 경우,
        <strong
          ><code>.end()</code> 또는 <code>.pipe()</code>를 호출하지
          마세요</strong
        >. <code>.then()</code> 또는 <code>await</code>를 사용하면 요청을 처리할
        수 있는 다른 방식들이 모두 비활성화됩니다.
      </p>
      <p>
        <a href="https://github.com/tj/co">co</a>와 같은 라이브러리나
        <a href="https://github.com/koajs/koa">koa</a>와 같은 웹
        프레임워크에서는 SuperAgent의 모든 메서드에서 <code>yield</code>를
        사용할 수 있습니다.
      </p>
      <pre><code class="language-javascript">    const req = request
      .get(&#39;http://local&#39;)
      .auth(&#39;tobi&#39;, &#39;learnboost&#39;);
    const res = yield req;
</code></pre>
      <p>
        SuperAgent는 전역 <code>Promise</code> 객체가 존재하는 환경에서
        동작하도록 설계되어 있습니다. Internet Explorer나 Node.js 0.10에서
        promise를 사용하려면 v7 버전과 폴리필이 필요합니다.
      </p>
      <p>
        v8 버전부터는 IE에 대한 지원이 중단되었습니다. Opera 85나 iOS Safari
        12.2–12.5 등을 지원하려면 WeakRef와 BigInt에 대한 폴리필을 추가해야
        합니다. 예를 들어
        <a href="https://cdnjs.cloudflare.com/polyfill/"
          >https://cdnjs.cloudflare.com/polyfill/</a
        >을 사용할 수 있습니다.
      </p>
      <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;
</code></pre>
      <h2 id="browser-and-node-versions">브라우저와 node 버전</h2>
      <p>
        SuperAgent에는 두 가지 구현 방식이 있습니다. 하나는 웹 브라우저용(XHR
        사용)이고, 다른 하나는 Node.JS용(core http 모듈 사용)입니다. 기본적으로
        Browserify와 WebPack은 브라우저 버전을 선택합니다.
      </p>
      <p>
        Node.JS용 코드를 컴파일하려면 WebPack 설정에서 반드시
        <a href="https://webpack.github.io/../configuration.html#target"
          >node target</a
        >
        을 지정해야 합니다.
      </p>
    </div>
    <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>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
      $('code').each(function () {
        $(this).html(highlight($(this).text()));
      });

      function highlight(js) {
        return js
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/('.*?')/gm, '<span class="string">$1</span>')
          .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
          .replace(/(\d+)/gm, '<span class="number">$1</span>')
          .replace(
            /\bnew *(\w+)/gm,
            '<span class="keyword">new</span> <span class="init">$1</span>'
          )
          .replace(
            /\b(function|new|throw|return|var|if|else)\b/gm,
            '<span class="keyword">$1</span>'
          );
      }
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js"></script>
    <script>
      // Only use tocbot for main docs, not test docs
      if (document.querySelector('#superagent')) {
        tocbot.init({
          // Where to render the table of contents.
          tocSelector: '#menu',
          // Where to grab the headings to build the table of contents.
          contentSelector: '#content',
          // Which headings to grab inside of the contentSelector element.
          headingSelector: 'h2',
          smoothScroll: false
        });
      }
    </script>
  </body>
</html>


================================================
FILE: docs/ko_KR/index.md
================================================
# SuperAgent

SuperAgent는 기존의 복잡한 요청 API에 대한 불만에서 출발해 유연성, 가독성, 그리고 낮은 학습 난이도를 목표로 설계된 경량 Ajax API입니다. 또한 Node.js 환경에서도 동작합니다!

```javascript
request
  .post('/api/pet')
  .send({ name: 'Manny', species: 'cat' })
  .set('X-API-Key', 'foobar')
  .set('Accept', 'application/json')
  .then((res) => {
    alert('yay got ' + JSON.stringify(res.body));
  });
```

## 테스트 문서

[**English**](/superagent/)

다음의 [테스트 문서](../test.html)는 [Mocha](https://mochajs.org/)의 "doc" 리포터를 사용해 생성되었으며, 실제 테스트 스위트를 직접 반영합니다.  
이 문서는 추가적인 참고 자료로 활용할 수 있습니다.

## 기본 요청

요청은 `request` 객체에서 적절한 메서드를 호출하여 시작되며, 그 다음 `.then()` 또는 `.end()` 혹은 [`await`](#promise-and-generator-support)를 사용해 요청을 전송할 수 있습니다. 예를 들어, 간단한 **GET** 요청은 다음과 같습니다.

```javascript
request
  .get('/search')
  .then((res) => {
    // res.body, res.headers, res.status
  })
  .catch((err) => {
    // err.message, err.response
  });
```

HTTP 메서드는 문자열로도 전달할 수 있습니다.

```javascript
request('GET', '/search').then(success, failure);
```

예전 방식의 콜백도 지원되지만, 권장되지는 않습니다. `.then()` 대신 `.end()`를 호출하여 요청을 전송할 수 있습니다.

```javascript
request('GET', '/search').end(function (err, res) {
  if (res.ok) {
  }
});
```

절대 URL을 사용할 수 있습니다. 단, 웹 브라우저에서는 서버가 [CORS](#cors)를 구현한 경우에만 절대 URL이 정상적으로 작동합니다.

```javascript
request.get('https://example.com/search').then((res) => {});
```

**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)을 통한 요청을 지원합니다.

```javascript
// pattern: https?+unix://SOCKET_PATH/REQUEST_PATH
//          Use `%2F` as `/` in SOCKET_PATH
try {
  const res = await request.get(
    'http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search'
  );
  // res.body, res.headers, res.status
} catch (err) {
  // err.message, err.response
}
```

**DELETE**, **HEAD**, **PATCH**, **POST**, **PUT** 요청도 사용할 수 있으며, 다음 예시에서 메서드 이름만 변경하면 됩니다.

```javascript
request.head('/favicon.ico').then((res) => {});
```

**DELETE**는 `delete`가 예약어였던 구형 IE와의 호환성을 위해 `.del()` 메서드로도 호출할 수 있습니다.

HTTP 메서드의 기본값은 **GET**이므로, 다음과 같이 작성해도 유효합니다.

```javascript
request('/search', (err, res) => {});
```

## HTTP/2 사용하기

HTTP/1.x 폴백 없이 HTTP/2 프로토콜만 사용하려면 `.http2()` 메서드를 호출하여 요청을 전송할 수 있습니다.

```javascript
const request = require('superagent');
const res = await request.get('https://example.com/h2').http2();
```

## 헤더 필드 설정하기

헤더 필드 설정은 간단합니다. 필드 이름과 값을 `.set()` 메서드에 전달하면 됩니다.

```javascript
request
  .get('/search')
  .set('API-Key', 'foobar')
  .set('Accept', 'application/json')
  .then(callback);
```

You may also pass an object to set several fields in a single call:

여러 개의 헤더 필드를 한 번에 설정하려면 객체를 전달하면 됩니다.

```javascript
request
  .get('/search')
  .set({ 'API-Key': 'foobar', Accept: 'application/json' })
  .then(callback);
```

## `GET` 요청

`.query()` 메서드는 객체를 인자로 받아 **GET** 요청 시 쿼리 문자열을 자동으로 생성합니다. 예를 들어 다음 코드는 `/search?query=Manny&range=1..5&order=desc` 경로를 생성합니다.

````js
request
  .get('/search')
  .query({ query: 'Manny', range: '1..5', order: 'desc' });


```javascript
request
  .get('/search')
  .query({ query: 'Manny' })
  .query({ range: '1..5' })
  .query({ order: 'desc' })
  .then((res) => {});
````

또는 하나의 객체로 설정할 수 있습니다.

```javascript
request
  .get('/search')
  .query({ query: 'Manny', range: '1..5', order: 'desc' })
  .then((res) => {});
```

`.query()` 메서드는 문자열도 받습니다.

```javascript
request
  .get('/querystring')
  .query('search=Manny&range=1..5')
  .then((res) => {});
```

조인할 수도 있습니다.

```javascript
request
  .get('/querystring')
  .query('search=Manny')
  .query('range=1..5')
  .then((res) => {});
```

## `HEAD` 요청하기

HEAD 요청에서도 `.query()` 메서드를 사용할 수 있습니다. 예를 들어 다음 코드는 `/users?email=joe@smith.com` 경로를 생성합니다.

```javascript
request
  .head('/users')
  .query({ email: 'joe@smith.com' })
  .then((res) => {});
```

## `POST` / `PUT` 요청

전형적인 JSON **POST** 요청은 Content-Type 헤더를 적절히 설정하고,  
데이터를 JSON 형식으로 전송하는 방식입니다. 예를 들어 다음과 같은 코드가 이에 해당합니다.

```javascript
request
  .post('/user')
  .set('Content-Type', 'application/json')
  .send('{"name":"tj","pet":"tobi"}')
  .then(callback)
  .catch(errorCallback);
```

JSON은 가장 일반적으로 사용되므로 기본값으로 설정되어 있습니다. 다음 예제는 앞선 예제와 동일한 동작을 수행합니다.

```javascript
request
  .post('/user')
  .send({ name: 'tj', pet: 'tobi' })
  .then(callback, errorCallback);
```

또는 `.send()` 여러 번 호출할 수 있습니다.

```javascript
request
  .post('/user')
  .send({ name: 'tj' })
  .send({ pet: 'tobi' })
  .then(callback, errorCallback);
```

기본적으로 문자열을 전송하면 `Content-Type`이 `application/x-www-form-urlencoded`로 자동 설정됩니다.  
여러 번 `.send()`를 호출하면 각 문자열이 `&`로 연결되어 최종적으로 `name=tj&pet=tobi`와 같은 결과가 생성됩니다.

```javascript
request
  .post('/user')
  .send('name=tj')
  .send('pet=tobi')
  .then(callback, errorCallback);
```

SuperAgent는 다양한 형식으로 확장 가능하지만, 기본적으로 "json"과 "form" 형식을 지원합니다. `application/x-www-form-urlencoded` 형식으로 데이터를 전송하려면 `.type('form')`을 호출하면 됩니다. 기본 형식은 `"json"`입니다. 다음 요청은 본문에 `"name=tj&pet=tobi"`를 포함하여 **POST**됩니다.

```javascript
request
  .post('/user')
  .type('form')
  .send({ name: 'tj' })
  .send({ pet: 'tobi' })
  .then(callback, errorCallback);
```

[`FormData`](https://developer.mozilla.org/ko/docs/Web/API/FormData/FormData) 객체를 사용하는 것도 지원됩니다. 다음 예제는 `id="myForm"`인 HTML 폼의 내용을 **POST** 방식으로 전송합니다.

```javascript
request
  .post('/user')
  .send(new FormData(document.getElementById('myForm')))
  .then(callback, errorCallback);
```

## `Content-Type` 설정하기

가장 명확한 해결책은 `.set()` 메서드를 사용하는 것입니다.

```javascript
request.post('/user').set('Content-Type', 'application/json');
```

간단하게 `.type()` 메서드를 사용할 수 있으며,  
표준화된 MIME 타입(`type/subtype`)을 직접 지정하거나  
"xml", "json", "png" 등과 같은 확장자 이름만으로도 설정할 수 있습니다.

```javascript
request.post('/user').type('application/json');

request.post('/user').type('json');

request.post('/user').type('png');
```

## 요청 본문 직렬화하기

SuperAgent는 기본적으로 JSON과 폼 데이터를 자동으로 직렬화합니다.  
또한 다른 콘텐츠 유형에 대해서도 자동 직렬화를 설정할 수 있습니다.

```js
request.serialize['application/xml'] = function (obj) {
  return 'string generated from obj';
};

// 'application/xml' Content-type을 가진 모든 요청은
// 자동으로 직렬화 됩니다.
```

사용자 정의 형식으로 페이로드를 전송하려면,  
요청 단위로 `.serialize()` 메서드를 사용해 SuperAgent의 기본 직렬화 방식을 교체할 수 있습니다.

```js
request
  .post('/user')
  .send({ foo: 'bar' })
  .serialize((obj) => {
    return 'string generated from obj';
  });
```

## 요청 재시도하기

`.retry()` 메서드를 사용하면, 일시적인 오류나 불안정한 인터넷 연결로 인해 요청이 실패한 경우 SuperAgent가 자동으로 재시도합니다.

이 메서드는 두 개의 선택적 인자를 받습니다. 재시도 횟수(기본값은 1)와 콜백 함수입니다. 각 재시도 전에 `callback(err, res)`를 호출합니다. 콜백 함수는 요청을 재시도할지 여부를 결정하기 위해 `true` 또는 `false`를 반환할 수 있습니다. 단, 최대 재시도 횟수는 항상 적용됩니다.

```javascript
     request
       .get('https://example.com/search')
       .retry(2) // 혹은
       .retry(2, callback)
       .then(finished);
       .catch(failed);
```

멱등한 요청인 경우에만 `.retry()` 메서드를 사용하세요. 예를 들어, 동일한 요청이 서버에 여러 번 도달하더라도 중복 구매와 같은 바람직하지 않은 부작용이 발생하지 않아야 합니다.

모든 요청 메서드는 기본적으로 재시도 대상에 포함됩니다. 따라서 POST 요청을 재시도하지 않도록 하려면, 사용자 정의 재시도 콜백을 전달해야 합니다.

기본적으로 다음과 같은 상태 코드는 자동으로 재시도됩니다.

- `408`
- `413`
- `429`
- `500`
- `502`
- `503`
- `504`
- `521`
- `522`
- `524`

기본적으로 다음과 같은 오류 코드가 자동으로 재시도됩니다.

- `'ETIMEDOUT'`
- `'ECONNRESET'`
- `'EADDRINUSE'`
- `'ECONNREFUSED'`
- `'EPIPE'`
- `'ENOTFOUND'`
- `'ENETUNREACH'`
- `'EAI_AGAIN'`

## Accept 설정하기

`.type()` 메서드와 유사하게, `.accept()` 메서드를 사용하면 `Accept` 헤더를 간편하게 설정할 수 있습니다. 이 메서드는 `request.types`를 참조하며, `type/subtype` 형식의 MIME 타입 전체 이름이나 "xml", "json", "png" 등의 확장자 형태로도 지정할 수 있어 편리합니다.

```javascript
request.get('/user').accept('application/json');

request.get('/user').accept('json');

request.post('/user').accept('png');
```

### Facebook과 Accept JSON

Facebook 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)에서 확인해보세요.

## 쿼리 문자열

`req.query(obj)`는 쿼리 문자열을 구성하는 데 사용되는 메서드입니다. 예를 들어 **POST** 요청에서 `?format=json&dest=/login`과 같은 쿼리 문자열을 추가할 수 있습니다.

```javascript
request
  .post('/')
  .query({ format: 'json' })
  .query({ dest: '/login' })
  .send({ post: 'data', here: 'wahoo' })
  .then(callback);
```

기본적으로 쿼리 문자열은 특정한 순서로 조립되지 않습니다. ASCII 순으로 정렬된 쿼리 문자열을 사용하려면 `req.sortQuery()`를 호출하면 됩니다. 또한 `req.sortQuery(myComparisonFn)`을 통해 사용자 정의 정렬 비교 함수를 전달할 수도 있습니다. 비교 함수는 두 개의 인자를 받아 음수, 0 또는 양수를 반환해야 합니다.

```js
// 기본 정렬 방식
request
  .get('/user')
  .query('name=Nick')
  .query('search=Manny')
  .sortQuery()
  .then(callback);

// 사용자 정의 정렬 함수
request
  .get('/user')
  .query('name=Nick')
  .query('search=Manny')
  .sortQuery((a, b) => a.length - b.length)
  .then(callback);
```

## TLS 옵션

Node.js에서 SuperAgent는 HTTPS 요청을 구성할 수 있는 다양한 메서드를 지원합니다.

- `.ca()`: 신뢰할 CA 인증서를 설정합니다.
- `.cert()`: 클라이언트 인증서 체인을 설정합니다.
- `.key()`: 클라이언트의 개인 키를 설정합니다.
- `.pfx()`: PKCS12 형식의 PFX 파일을 사용하여 클라이언트의 개인 키와 인증서 체인을 설정합니다.
- `.disableTLSCerts()`: 만료되었거나 유효하지 않은 TLS 인증서를 거부하지 않도록 설정합니다. 내부적으로 `rejectUnauthorized=true`가 설정되며, 중간자 공격(MITM)에 노출될 수 있으므로 주의가 필요합니다.

더 자세한 내용은 Node.js [https.request 문서](https://nodejs.org/api/https.html#https_https_request_options_callback)에서 확인할 수 있습니다.

```js
var key = fs.readFileSync('key.pem'),
  cert = fs.readFileSync('cert.pem');

request.post('/client-auth').key(key).cert(cert).then(callback);
```

```js
var ca = fs.readFileSync('ca.cert.pem');

request
  .post('https://localhost/private-ca-server')
  .ca(ca)
  .then((res) => {});
```

## Parsing response bodies

## 응답 본문 파싱하기

SuperAgent will parse known response-body data for you,
currently supporting `application/x-www-form-urlencoded`,
`application/json`, and `multipart/form-data`. You can setup
automatic parsing for other response-body data as well:

SuperAgent는 응답 본문 데이터를 자동으로 파싱해줍니다.  
현재 `application/x-www-form-urlencoded`, `application/json`, `multipart/form-data`을 지원합니다. 이외의 응답 본문 데이터에 대해서도 자동 파싱을 설정할 수 있습니다.

```js
// 브라우저
request.parse['application/xml'] = function (str) {
  return { object: 'parsed from str' };
};

// node
request.parse['application/xml'] = function (res, cb) {
  // 응답 문자를 파싱하고 res.body를 여기서 설정하세요

  cb(null, res);
};

// 앞으로 'application/xml' 유형의 반응은
// 자동으로 파싱됩니다
```

`.buffer(true).parse(fn)` 메서드를 사용하면 내장된 파서보다 우선적으로 적용되는 사용자 정의 파서를 설정할 수 있습니다. `.buffer(false)`로 응답 버퍼링이 비활성화되어 있다면, `response` 이벤트는 본문 파싱이 완료되기 전에 발생하므로 `response.body`를 사용할 수 없습니다.

### JSON / Urlencoded

`res.body` 속성은 파싱된 객체를 나타냅니다. 예를 들어, 응답이 JSON 문자열 `{"user":{"name":"tobi"}}`를 반환했다면, `res.body.user.name`은 "tobi" 값을 갖게 됩니다. 마찬가지로 x-www-form-urlencoded 형식의 "user[name]=tobi"도 동일한 결과를 제공합니다. 단, 중첩은 한 단계까지만 지원되므로 더 복잡한 구조의 데이터를 다루려면 JSON 형식을 사용하는 것이 좋습니다.

배열은 key를 반복해서 전달하는 방식으로 전송됩니다. 예를 들어, `.send({ color: ['red', 'blue'] })`는 `color=red&color=blue`로 변환되어 전송됩니다. 배열의 key에 `[]`를 포함시키고 싶다면 SuperAgent는 이를 자동으로 처리하지 않으므로, 직접 `color[]`와 같이 key 이름에 대괄호를 추가해야 합니다.

### 다중 파트

Node 클라이언트는 [Formidable](https://github.com/felixge/node-formidable) 모듈을 통해 *multipart/form-data*를 지원합니다.  
다중 파트 응답을 파싱할 때 `res.files` 객체를 사용할 수 있으며, 이 객체에는 업로드된 파일에 대한 정보가 포함됩니다. 예를 들어, 다음과 같은 multipart 본문을 포함한 응답을 가정해볼 수 있습니다.

    --whoop
    Content-Disposition: attachment; name="image"; filename="tobi.png"
    Content-Type: image/png

    ... data here ...
    --whoop
    Content-Disposition: form-data; name="name"
    Content-Type: text/plain

    Tobi
    --whoop--

`res.body.name`은 "Tobi" 값을 가지고 있으며, `res.files.image`는 디스크 경로, 파일 이름 및 기타 속성을 포함한 `File` 객체입니다.

### 바이너리

브라우저에서는 바이너리 응답 본문을 처리하기 위해 `.responseType('blob')`을 사용할 수 있습니다. 이 API는 Node.js 환경에서는 필요하지 않습니다. 이 메서드에서 지원되는 인자 값은 다음과 같습니다.

- `'blob'`는 XMLHttpRequest의 `responseType` 속성에 그대로 전달됩니다.
- `'arraybuffer'`도 마찬가지로 `responseType` 속성에 전달됩니다.

```js
req
  .get('/binary.data')
  .responseType('blob')
  .then((res) => {
    // 여기서 res.body는 브라우저 기본 Blob 타입입니다.
  });
```

더 자세한 내용은 Mozilla Developer Network의 [XMLHttpRequest.responseType 문서](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)에서 확인할 수 있습니다.

## 응답 속성

`Response` 객체에는 응답 텍스트, 파싱된 응답 본문, 헤더 필드, 상태 플래그 등 다양한 유용한 플래그와 속성이 설정되어 있습니다.

### 응답 문자

`res.text` 속성에는 파싱되지 않은 응답 본문 문자열이 포함됩니다. 이 속성은 클라이언트 API에서는 항상 존재하며, Node 환경에서는 MIME 타입이 "text/_", "_/json", "x-www-form-urlencoded"와 일치할 경우에만 기본적으로 제공됩니다. 이러한 제한은 대용량 multipart 파일이나 이미지 등의 본문을 텍스트로 버퍼링하는 것이 매우 비효율적이기 때문에 메모리를 절약하기 위한 목적입니다. 응답을 강제로 버퍼링하려면 "응답 버퍼링" 섹션을 참조하세요.

### 응답 본문

SuperAgent는 요청 데이터를 자동으로 직렬화할 뿐만 아니라, 자동으로 파싱할 수도 있습니다. Content-Type에 대해 파서가 정의되어 있는 경우, 해당 타입에 맞게 응답이 파싱되며 기본적으로 "application/json"과 "application/x-www-form-urlencoded" 형식이 포함됩니다. 파싱된 객체는 `res.body`를 통해 접근할 수 있습니다.

### 응답 헤더 필드

`res.header`는 파싱된 응답 헤더 필드를 담은 객체로, Node.js와 마찬가지로 필드 이름을 소문자로 변환하여 저장합니다.  
예를 들어, `res.header['content-length']`와 같이 접근할 수 있습니다.

### 응답 콘텐츠 타입

Content-Type 응답 헤더는 특별하게 처리되어 `res.type` 속성은 charset 정보를 제외한 콘텐츠 타입만을 제공합니다. 예를 들어 Content-Type이 "text/html; charset=utf8"인 경우, `res.type`은 "text/html"을 반환하고, `res.charset` 속성에는 "utf8"이 포함됩니다.

### 응답 상태

응답 상태 플래그는 요청이 성공했는지 여부를 비롯한 다양한 유용한 정보를 판단하는 데 도움을 줍니다. 이를 통해 SuperAgent는 RESTful 웹 서비스와 효과적으로 상호작용할 수 있습니다. 현재 정의된 주요 플래그는 다음과 같습니다.

```javascript
var type = (status / 100) | 0;

// 상태 / 클래스
res.status = status;
res.statusType = type;

// 기본
res.info = 1 == type;
res.ok = 2 == type;
res.clientError = 4 == type;
res.serverError = 5 == type;
res.error = 4 == type || 5 == type;

// 편의 기능
res.accepted = 202 == status;
res.noContent = 204 == status || 1223 == status;
res.badRequest = 400 == status;
res.unauthorized = 401 == status;
res.notAcceptable = 406 == status;
res.notFound = 404 == status;
res.forbidden = 403 == status;
```

## 요청 중단하기

요청을 중단하려면 `req.abort()` 메서드를 호출하기만 하면 됩니다.

## 타임아웃

때때로 네트워크나 서버가 요청을 수신한 후 응답 없이 멈춰버리는 경우가 있습니다. 이러한 무한 대기를 방지하려면 타임아웃을 설정해야 합니다.

- `req.timeout({deadline: ms})` 또는 `req.timeout(ms)`는 업로드, 리다이렉트, 서버 처리 시간을 포함한 전체 요청이 완료되어야 하는 최종 시간 제한을 설정합니다. `ms`는 0보다 큰 밀리초 단위의 숫자이며, 제한 시간 내에 응답이 완료되지 않으면 요청은 중단됩니다.

- `req.timeout({response: ms})`는 서버로부터 첫 번째 바이트가 도착할 때까지의 최대 대기 시간을 설정합니다. 전체 다운로드 소요 시간은 제한하지 않습니다. 응답 타임아웃은 DNS 조회, TCP/IP 및 TLS 연결, 요청 데이터 업로드 시간을 포함하므로, 서버의 실제 응답 시간보다 몇 초 더 길게 설정하는 것이 좋습니다.

`deadline`과 `response` 타임아웃은 함께 사용하는 것이 좋습니다. 짧은 응답 타임아웃은 응답하지 않는 네트워크를 빠르게 감지하는 데 유용하고, 긴 데드라인은 느리지만 안정적인 네트워크 환경에서 다운로드를 완료할 수 있도록 여유 시간을 제공합니다. 두 타이머 모두 첨부된 파일 업로드에 허용되는 시간을 제한합니다. 파일을 업로드하는 경우에는 충분히 긴 타임아웃을 설정하는 것이 좋습니다.

```javascript
request
  .get('/big-file?network=slow')
  .timeout({
    response: 5000, // 서버가 데이터를 보내기 시작할 때까지 최대 5초간 기다립니다.
    deadline: 60000 // 파일 전체를 로드하는 데 최대 1분까지 허용합니다.
  })
  .then(
    (res) => {
      /* 제시간 응답 수신 */
    },
    (err) => {
      if (err.timeout) {
        /* 시간 초과! */
      } else {
        /* 그 외 오류 */
      }
    }
  );
```

타임아웃 오류에는 `.timeout` 속성이 포함되어 있습니다.

## 인증

Node와 브라우저 환경에서 `.auth()` 메서드를 사용하여 인증을 수행할 수 있습니다.

```javascript
request.get('http://local').auth('tobi', 'learnboost').then(callback);
```

_Node_ 클라이언트에서는 기본 인증을 URL 내에 "user:pass" 형식으로 포함시킬 수 있습니다.

```javascript
request.get('http://tobi:learnboost@local').then(callback);
```

기본적으로 `Basic` 인증만 사용됩니다. 브라우저에서는 `{type: 'auto'}`를 추가하면 Digest, NTLM 등 브라우저에 내장된 모든 인증 방식을 사용할 수 있습니다.

```javascript
request.auth('digest', 'secret', { type: 'auto' });
```

`auth` 메서드는 토큰 기반 인증을 위한 `type: 'bearer'` 옵션도 지원합니다.

```javascript
request.auth('my_token', { type: 'bearer' });
```

## 다음 리다이렉션 따라가기

기본적으로 최대 5번까지 리다이렉션이 자동으로 따라가며, 필요에 따라 `res.redirects(n)` 메서드를 사용하여 이 횟수를 지정할 수 있습니다.

```javascript
const response = await request.get('/some.png').redirects(2);
```

리다이렉션 횟수가 제한을 초과하면 오류로 간주됩니다. 이를 성공적인 응답으로 처리하려면 `.ok(res => res.status < 400)` 메서드를 사용하세요.

## 전역 상태를 위한 에이전트

### 쿠키 저장하기

Node에서 SuperAgent는 기본적으로 쿠키를 저장하지 않습니다. 하지만 `.agent()` 메서드를 사용하면 쿠키를 저장하는 SuperAgent 인스턴스를 생성할 수 있습니다. 각 인스턴스는 독립적인 쿠키 저장소를 가지고 있습니다.

```javascript
const agent = request.agent();
agent.post('/login').then(() => {
  return agent.get('/cookied-page');
});
```

브라우저에서는 쿠키가 자동으로 관리되므로 `.agent()`를 사용해도 쿠키가 분리되지는 않습니다.

### 다중 요청을 위한 기본 옵션

에이전트에서 호출된 일반 요청 메서드는 해당 에이전트가 처리하는 모든 요청에 대해 기본값으로 적용됩니다.

```javascript
const agent = request.agent().use(plugin).auth(shared);

await agent.get('/with-plugin-and-auth');
await agent.get('/also-with-plugin-and-auth');
```

에이전트가 기본 옵션을 설정할 수 있도록 지원하는 메서드 목록입니다. `use`, `on`, `once`, `set`, `query`, `type`, `accept`, `auth`, `withCredentials`, `sortQuery`, `retry`, `ok`, `redirects`, `timeout`, `buffer`, `serialize`, `parse`, `ca`, `key`, `pfx`, `cert`.

## 데이터 전달 방식

`.pipe()`는 `.end()` 또는 `.then()` 메서드 **대신** 사용되며, Node 클라이언트는 요청과 응답 간에 데이터를 주고받도록 파이프 처리할 수 있습니다.

예를 들어, 파일의 콘텐츠를 요청 본문으로 전달하는 경우는 다음과 같습니다.

```javascript
const request = require('superagent');
const fs = require('fs');

const stream = fs.createReadStream('path/to/my.json');
const req = request.post('/somewhere');
req.type('json');
stream.pipe(req);
```

요청에 데이터를 파이프할 경우, SuperAgent는 해당 데이터를 [청크 전송 인코딩](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) 방식으로 전송합니다. 이 방식은 Python WSGI 서버 등 모든 서버에서 지원되지는 않습니다.

응답을 파일로 저장하려면 다음과 같이 파이프 처리할 수 있습니다.

```javascript
const stream = fs.createWriteStream('path/to/my.json');
const req = request.get('/some.json');
req.pipe(stream);
```

파이프와 콜백 또는 프로미스는 **함께 사용할 수 없으며**, `.end()`나 `Response` 객체의 결과를 파이프 처리해서는 안 됩니다.

```javascript
// 이러한 방식으로 하지 마세요.
const stream = getAWritableStream();
const req = request
  .get('/some.json')
  // 나쁨: 이 방식은 스트림에 올바르지 않은 데이터를 전달하며 예기치 못한 방식으로 실패할 수 있습니다.
  .end((err, this_does_not_work) => this_does_not_work.pipe(stream));
const req = request
  .get('/some.json')
  .end()
  // 나쁨: 이 방식도 지원되지 않으며, .pipe는 자동으로 .end를 호출합니다.
  .pipe(nope_its_too_late);
```

SuperAgent의 [향후 버전](https://github.com/ladjs/superagent/issues/1188)에서는 `pipe()`를 부적절하게 호출하면 실패하게 됩니다.

## 다중 부분 요청

`.attach()`와 `.field()` 메서드를 제공하는 SuperAgent는 다중 부분 요청을 구성하는 데에도 매우 유용합니다.

`.field()` 또는 `.attach()`를 사용할 경우 `.send()`는 사용할 수 없으며, `Content-Type` 헤더를 직접 설정해서는 안 됩니다. 올바른 타입은 자동으로 지정됩니다.

### 파일 첨부하기

`.attach(name, [file], [options])`를 사용하여 파일을 전송할 수 있습니다. 여러 파일을 첨부하려면 `.attach`를 반복 호출하면 됩니다. 인자는 다음과 같습니다.

- `name` — 폼 이름 필드
- `file` — 파일 경로의 문자열 또는 `Blob`/`Buffer` 객체.
- `options` — (선택) 사용자 정의 파일 이름의 문자열 또는 `{filename: string}` 형식의 객체. Node 환경에서는 `{contentType: 'mime/type'}`도 지원하며 브라우저에서는 적절한 타입의 `Blob` 객체를 생성해야 합니다.

<br>

```javascript
request
  .post('/upload')
  .attach('image1', 'path/to/felix.jpeg')
  .attach('image2', imageBuffer, 'luna.jpeg')
  .field('caption', 'My cats')
  .then(callback);
```

### 필드 값

`.field(name, value)` 및 `.field({name: value})`를 사용해 HTML 폼 필드처럼 값을 설정할 수 있습니다. 예를 들어 이름과 이메일 정보를 함께 여러 이미지를 업로드하려면, 요청은 다음과 같이 구성될 수 있습니다.

```javascript
request
  .post('/upload')
  .field('user[name]', 'Tobi')
  .field('user[email]', 'tobi@learnboost.com')
  .field('friends[]', ['loki', 'jane'])
  .attach('image', 'path/to/tobi.png')
  .then(callback);
```

## 압축

node 클라이언트는 압축된 응답을 지원하며, 아무 것도 하지 않아도 됩니다! 그냥 작동합니다.

## 응답 버퍼링

To 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)`.

`.req.buffer()`를 호출하면 응답 본문을 `res.text`로 강제 버퍼링할 수 있습니다. "text/plain", "text/html" 등 텍스트 응답의 기본 버퍼링을 취소하려면 `.req.buffer(false)`를 호출하세요.

`res.buffered` 플래그가 제공되면, 이를 활용하여 동일한 콜백 함수에서 버퍼링된 응답과 버퍼링되지 않은 응답을 모두 처리할 수 있습니다.

## CORS

보안상의 이유로 브라우저는 서버가 CORS 헤더를 통해 명시적으로 허용하지 않으면 교차 출처 요청(cross-origin requests)을 차단합니다. 브라우저는 또한 서버가 어떤 HTTP 헤더와 메서드를 허용하는지 확인하기 위해 추가적인 **OPTIONS** 요청을 전송합니다. [CORS에 대해 더 알아보기](https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CORS).

`.withCredentials()` 메서드는 origin(출처)에서 쿠키를 전송할 수 있도록 활성화합니다. 단, 이 기능은 `Access-Control-Allow-Origin` 값이 와일드카드("\*")가 _아니어야_ 하며, `Access-Control-Allow-Credentials` 값이 `"true"`일 경우에만 작동합니다.

```javascript
request
  .get('https://api.example.com:4001/')
  .withCredentials()
  .then((res) => {
    assert.equal(200, res.status);
    assert.equal('tobi', res.text);
  });
```

## 오류 처리하기

콜백 함수는 항상 두 개의 인자를 전달합니다. 오류와 응답입니다. 오류가 발생하지 않으면, 첫 번째 인자는 null 입니다.

```javascript
request
  .post('/upload')
  .attach('image', 'path/to/tobi.png')
  .then((res) => {});
```

"error" 이벤트도 발생하며, 이를 통해 오류를 감지하고 처리할 수 있습니다.

```javascript
request
  .post('/upload')
  .attach('image', 'path/to/tobi.png')
  .on('error', handle)
  .then((res) => {});
```

**SuperAgent는 기본적으로 4xx 및 5xx 응답(그리고 처리되지 않은 3xx 응답도 포함)을 오류**로 간주합니다. 예를 들어 `304 Not Modified`, `403 Forbidden`, `500 Internal Server Error` 같은 응답을 받으면 해당 상태 정보는 `err.status`를 통해 확인할 수 있습니다. 이러한 응답으로부터 발생한 오류에는 "[응답 요소](#response-properties)"에서 언급한 모든 속성을 포함한 `err.response` 필드도 포함됩니다. 이 라이브러리는 일반적으로 성공 응답만을 원하고, HTTP 오류 상태 코드를 오류로 처리하는 경우를 대비하여 이러한 방식으로 동작합니다. 하지만 특정 오류 조건에 대해서는 사용자 정의 로직을 허용하도록 설계되어 있습니다.

네트워크 실패, 시간초과, 응답 없는 오류는 `err.status` 또는 `err.response` 필드를 포함하지 않습니다.

404 또는 HTTP 오류 응답을 처리하고 싶다면, `error.status` 요소를 사용할 수 있습니다. HTTP 오류(4xx 또는 5xx 응답)가 발생했을 때 `res.error` 요소는 `Error` 객체이고 이는 다음과 같이 에러 확인을 수행할 수 있습니다.

```javascript
if (err && err.status === 404) {
  alert('oh no ' + res.body.message);
} else if (err) {
  // 그 외 다른 모든 오류 유형은 일반적으로 처리합니다
}
```

대안으로, `.ok(callback)` 메서드를 사용하여 응답이 오류인지 아닌지 결정할 수 있습니다. `ok` 콜백은 응답을 받고 응답이 성공으로 해석되면 `true`를 반환합니다.

```javascript
request
  .get('/404')
  .ok((res) => res.status < 500)
  .then((response) => {
    // 404 페이지를 성공적인 응답으로 처리합니다
  });
```

## 진행과정 추적하기

SuperAgent는 업로드와 큰 파일 다운로드에서 `progress` 이벤트를 동작시킵니다.

```javascript
request
  .post(url)
  .attach('field_name', file)
  .on('progress', (event) => {
    /* 이벤트 객체는 다음과 같습니다.
        {
          direction: "upload" or "download"
          percent: 0 to 100 // 0에서 100까지 (파일 크기를 알 수 없는 경우 생략될 수 있습니다)
          total: // 전체 파일 크기 (생략될 수 있습니다)
          loaded: // 현재까지 다운로드되거나 업로드된 바이트 수
        } */
  })
  .then();
```

## 로컬 호스트에서 테스트하기

### 특정 IP 주소 연결 설정하기

In 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`:

Node.js에서는 DNS를 무시하고 `.connect()` 메서드를 사용하여 모든 요청을 특정 IP 주소로 직접 연결할 수 있습니다. 예를 들어, 이 요청은 `example.com` 대신 로컬호스트로 전달됩니다.

```javascript
const res = await request.get('http://example.com').connect('127.0.0.1');
```

요청은 리다이렉트 되어, 여러 호스트명과 IP를 특정지을 수 있으며 특별한 `*`를 대체로 설정할 수 있습니다. (다른 와일드 카드는 지원되지 않습니다). 요청은 원본 값을 가지며 본인의 `Host` 헤더를 유지합니다. `.connect(undefined)`는 이러한 기능을 끕니다.

```javascript
const res = await request.get('http://redir.example.com:555').connect({
  'redir.example.com': '127.0.0.1', // redir.example.com:555는 127.0.0.1:555를 사용합니다.
  'www.example.com': false, // 이 항목은 재정의하지 마세요. 일반적인 DNS 설정을 사용합니다.
  'mapped.example.com': { host: '127.0.0.1', port: 8080 }, // mapped.example.com의 모든 포트는 127.0.0.1:8080으로 매핑됩니다.
  '*': 'proxy.example.com' // 나머지 모든 요청은 이 호스트로 전달됩니다
});
```

### 로컬 호스트에서 깨지거나 보안되지 않은 HTTPS 무시하기

Node.js에서 HTTPS 설정이 잘못되었거나 보안성이 떨어지는 경우(예: 자체 서명된 인증서를 사용하면서 `.ca()`를 지정하지 않은 경우), `.trustLocalhost()`를 호출하면 `localhost`로의 요청을 허용할 수 있습니다.

```javascript
const res = await request.get('https://localhost').trustLocalhost();
```

`.connect("127.0.0.1")`와 함께 사용하면 HTTPS 요청을 어떤 도메인에서든 `localhost`로 강제로 리다이렉트할 수 있습니다.

`localhost`는 신뢰되지 않은 네트워크에 노출되지 않는 루프백 인터페이스이기 때문에, 깨진 HTTPS를 무시하는 것이 일반적으로 안전합니다. `localhost`를 신뢰하도록 설정하는 것이 향후 기본값이 될 수 있습니다. `127.0.0.1`의 진위 여부를 강제로 검사하려면 `.trustLocalhost(false)`를 사용하세요.

다른 IP 주소로 요청을 보낼 때 HTTPS 보안을 비활성화하는 기능은 의도적으로 지원하지 않습니다. 이러한 옵션은 HTTPS 문제를 빠르게 "해결"하려는 방식으로 오용되는 경우가 많기 때문입니다. [Let's Encrypt](https://certbot.eff.org)를 통해 무료 HTTPS 인증서를 발급받거나, `.ca(ca_public_pem)`을 사용해 자체 서명된 인증서를 신뢰할 수 있도록 직접 CA를 설정할 수 있습니다.

## Promise 및 Generator 지원

SuperAgent의 요청은 "thenable" 객체이며, JavaScript의 Promise 및 `async`/`await` 문법과 호환됩니다.

```javascript
const res = await request.get(url);
```

Promise를 사용할 경우, **`.end()` 또는 `.pipe()`를 호출하지 마세요**. `.then()` 또는 `await`를 사용하면 요청을 처리할 수 있는 다른 방식들이 모두 비활성화됩니다.

[co](https://github.com/tj/co)와 같은 라이브러리나 [koa](https://github.com/koajs/koa)와 같은 웹 프레임워크에서는 SuperAgent의 모든 메서드에서 `yield`를 사용할 수 있습니다.

```javascript
    const req = request
      .get('http://local')
      .auth('tobi', 'learnboost');
    const res = yield req;
```

SuperAgent는 전역 `Promise` 객체가 존재하는 환경에서 동작하도록 설계되어 있습니다. Internet Explorer나 Node.js 0.10에서 promise를 사용하려면 v7 버전과 폴리필이 필요합니다.

v8 버전부터는 IE에 대한 지원이 중단되었습니다. Opera 85나 iOS Safari 12.2–12.5 등을 지원하려면 WeakRef와 BigInt에 대한 폴리필을 추가해야 합니다. 예를 들어 <https://cdnjs.cloudflare.com/polyfill/>을 사용할 수 있습니다.

```html
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=WeakRef,BigInt"></script>
```

## 브라우저와 node 버전

SuperAgent에는 두 가지 구현 방식이 있습니다. 하나는 웹 브라우저용(XHR 사용)이고, 다른 하나는 Node.JS용(core http 모듈 사용)입니다. 기본적으로 Browserify와 WebPack은 브라우저 버전을 선택합니다.

Node.JS용 코드를 컴파일하려면 WebPack 설정에서 반드시 [node target](https://webpack.github.io/docs/configuration.html#target)을 지정해야 합니다.


================================================
FILE: docs/style.css
================================================
body {
  padding: 40px 80px;
  font: 14px/1.5 "Helvetica Neue", Helvetica, sans-serif;
  background: #181818 url(images/bg.png);
  text-align: center;
}

#content {
  margin: 0 auto;
  padding: 10px 40px;
  text-align: left;
  background: white;
  width: 50%;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  border-radius: 2px;
  -webkit-box-shadow: 0 2px 5px 0 black;
}

#menu {
  font-size: 13px;
  margin: 0;
  padding: 0;
  text-align: left;
  position: fixed;
  top: 15px;
  left: 15px;
}

#menu ul {
  margin: 0;
  padding: 0;
}

#menu li {
  list-style: none;
}

#menu a {
  color: rgba(255,255,255,.5);
  text-decoration: none;
}

#menu a:hover {
  color: white;
}

#menu .active a {
  color: white;
}

pre {
  padding: 10px;
}

code {
  font-family: monaco, monospace, sans-serif;
  font-size: 0.85em;
}

p code {
  border: 1px solid #ECEA75;
  padding: 1px 3px;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  border-radius: 2px;
  background: #FDFCD1;
}

pre {
  padding: 20px 25px;
  border: 1px solid #ddd;
  -webkit-box-shadow: inset 0 0 5px #eee;
  -moz-box-shadow: inset 0 0 5px #eee;
  box-shadow: inset 0 0 5px #eee;
  overflow: scroll;
}

code .comment { color: #ddd }
code .init { color: #2F6FAD }
code .string { color: #5890AD }
code .keyword { color: #8A6343 }
code .number { color: #2F6FAD }

/* override tocbot style to avoid vertical white line in table of content */
.toc-link::before {
  content: initial;
}


================================================
FILE: docs/tail.html
================================================
    </div>
    <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>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script>
      $('code').each(function(){
        $(this).html(highlight($(this).text()));
      });

      function highlight(js) {
        return js
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/('.*?')/gm, '<span class="string">$1</span>')
          .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
          .replace(/(\d+)/gm, '<span class="number">$1</span>')
          .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
          .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
      }
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.js"></script>
    <script>
      // Only use tocbot for main docs, not test docs
      if (document.querySelector('#superagent')) {
        tocbot.init({
          // Where to render the table of contents.
          tocSelector: '#menu',
          // Where to grab the headings to build the table of contents.
          contentSelector: '#content',
          // Which headings to grab inside of the contentSelector element.
          headingSelector: 'h2',
          smoothScroll: false
        });
      }
    </script>
  </body>
</html>


================================================
FILE: docs/test.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8">
    <title>SuperAgent — elegant API for AJAX in Node and browsers</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/3.0.0/tocbot.css">
    <link rel="stylesheet" href="docs/style.css">
  </head>
  <body>
    <ul id="menu"></ul>
    <div id="content">
test on node with http1
test on plain node
    <section class="suite">
      <h1>Agent</h1>
      <dl>
        <dt>should remember defaults</dt>
        <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
let called = 0;
let event_called = 0;
const agent = request
  .agent()
  .accept(&#x27;json&#x27;)
  .use(() =&#x3E; {
    called++;
  })
  .once(&#x27;request&#x27;, () =&#x3E; {
    event_called++;
  })
  .query({ hello: &#x27;world&#x27; })
  .set(&#x27;X-test&#x27;, &#x27;testing&#x27;);
assert.equal(0, called);
assert.equal(0, event_called);
return agent
  .get(&#x60;${base}/echo&#x60;)
  .then((res) =&#x3E; {
    assert.equal(1, called);
    assert.equal(1, event_called);
    assert.equal(&#x27;application/json&#x27;, res.headers.accept);
    assert.equal(&#x27;testing&#x27;, res.headers[&#x27;x-test&#x27;]);
    return agent.get(&#x60;${base}/querystring&#x60;);
  })
  .then((res) =&#x3E; {
    assert.equal(2, called);
    assert.equal(2, event_called);
    assert.deepEqual({ hello: &#x27;world&#x27; }, res.body);
  });</code></pre></dd>
      </dl>
    </section>
    <section class="suite">
      <h1>request</h1>
      <dl>
        <section class="suite">
          <h1>res.statusCode</h1>
          <dl>
            <dt>should set statusCode</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {
  try {
    assert.strictEqual(res.statusCode, 200);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>should allow the send shorthand</h1>
          <dl>
            <dt>with callback in the method call</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {
  assert.equal(res.status, 200);
  done();
});</code></pre></dd>
            <dt>with data in the method call</dt>
            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }).end((error, res) =&#x3E; {
  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);
  done();
});</code></pre></dd>
            <dt>with callback and data in the method call</dt>
            <dd><pre><code>request.post(&#x60;${uri}/echo&#x60;, { foo: &#x27;bar&#x27; }, (error, res) =&#x3E; {
  assert.equal(&#x27;{&#x22;foo&#x22;:&#x22;bar&#x22;}&#x27;, res.text);
  done();
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>with a callback</h1>
          <dl>
            <dt>should invoke .end()</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;, (error, res) =&#x3E; {
  try {
    assert.equal(res.status, 200);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>.end()</h1>
          <dl>
            <dt>should issue a request</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(res.status, 200);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
            <dt>is optional with a promise</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
return request
  .get(&#x60;${uri}/login&#x60;)
  .then((res) =&#x3E; res.status)
  .then()
  .then((status) =&#x3E; {
    assert.equal(200, status, &#x27;Real promises pass results through&#x27;);
  });</code></pre></dd>
            <dt>called only once with a promise</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
const request_ = request.get(&#x60;${uri}/unique&#x60;);
return Promise.all([request_, request_, request_]).then((results) =&#x3E; {
  for (const item of results) {
    assert.deepEqual(
      item.body,
      results[0].body,
      &#x27;It should keep returning the same result after being called once&#x27;
    );
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>res.error</h1>
          <dl>
            <dt>ok</dt>
            <dd><pre><code>let calledErrorEvent = false;
let calledOKHandler = false;
request
  .get(&#x60;${uri}/error&#x60;)
  .ok((res) =&#x3E; {
    assert.strictEqual(500, res.status);
    calledOKHandler = true;
    return true;
  })
  .on(&#x27;error&#x27;, (error) =&#x3E; {
    calledErrorEvent = true;
  })
  .end((error, res) =&#x3E; {
    try {
      assert.ifError(error);
      assert.strictEqual(res.status, 500);
      assert(!calledErrorEvent);
      assert(calledOKHandler);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should be an Error object</dt>
            <dd><pre><code>let calledErrorEvent = false;
request
  .get(&#x60;${uri}/error&#x60;)
  .on(&#x27;error&#x27;, (error) =&#x3E; {
    assert.strictEqual(error.status, 500);
    calledErrorEvent = true;
  })
  .end((error, res) =&#x3E; {
    try {
      if (NODE) {
        res.error.message.should.equal(&#x27;cannot GET /error (500)&#x27;);
      } else {
        res.error.message.should.equal(&#x60;cannot GET ${uri}/error (500)&#x60;);
      }
      assert.strictEqual(res.error.status, 500);
      assert(error, &#x27;should have an error for 500&#x27;);
      assert.equal(error.message, &#x27;Internal Server Error&#x27;);
      assert(calledErrorEvent);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>with .then() promise</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
return request.get(&#x60;${uri}/error&#x60;).then(
  () =&#x3E; {
    assert.fail();
  },
  (err) =&#x3E; {
    assert.equal(err.message, &#x27;Internal Server Error&#x27;);
  }
);</code></pre></dd>
            <dt>with .ok() returning false</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
return request
  .get(&#x60;${uri}/echo&#x60;)
  .ok(() =&#x3E; false)
  .then(
    () =&#x3E; {
      assert.fail();
    },
    (err) =&#x3E; {
      assert.equal(200, err.response.status);
      assert.equal(err.message, &#x27;OK&#x27;);
    }
  );</code></pre></dd>
            <dt>with .ok() throwing an Error</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
return request
  .get(&#x60;${uri}/echo&#x60;)
  .ok(() =&#x3E; {
    throw new Error(&#x27;boom&#x27;);
  })
  .then(
    () =&#x3E; {
      assert.fail();
    },
    (err) =&#x3E; {
      assert.equal(200, err.status);
      assert.equal(200, err.response.status);
      assert.equal(err.message, &#x27;boom&#x27;);
    }
  );</code></pre></dd>
            <dt>with .ok() throwing an Error with status</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return;
}
return request
  .get(&#x60;${uri}/echo&#x60;)
  .ok(() =&#x3E; {
    const err = new Error(&#x27;boom&#x27;);
    err.status = 404;
    throw err;
  })
  .then(
    () =&#x3E; {
      assert.fail();
    },
    (err) =&#x3E; {
      assert.equal(404, err.status);
      assert.equal(200, err.response.status);
      assert.equal(err.message, &#x27;boom&#x27;);
    }
  );</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>res.header</h1>
          <dl>
            <dt>should be an object</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>set headers</h1>
          <dl>
            <dt>should only set headers for ownProperties of header</dt>
            <dd><pre><code>try {
  request
    .get(&#x60;${uri}/echo-headers&#x60;)
    .set(&#x27;valid&#x27;, &#x27;ok&#x27;)
    .end((error, res) =&#x3E; {
      if (
        !error &#x26;&#x26;
        res.body &#x26;&#x26;
        res.body.valid &#x26;&#x26;
        !res.body.hasOwnProperty(&#x27;invalid&#x27;)
      ) {
        return done();
      }
      done(error || new Error(&#x27;fail&#x27;));
    });
} catch (err) {
  done(err);
}</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>res.charset</h1>
          <dl>
            <dt>should be set when present</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {
  try {
    res.charset.should.equal(&#x27;utf-8&#x27;);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>res.statusType</h1>
          <dl>
            <dt>should provide the first digit</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {
  try {
    assert(!error, &#x27;should not have an error for success responses&#x27;);
    assert.equal(200, res.status);
    assert.equal(2, res.statusType);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>res.type</h1>
          <dl>
            <dt>should provide the mime-type void of params</dt>
            <dd><pre><code>request.get(&#x60;${uri}/login&#x60;).end((error, res) =&#x3E; {
  try {
    res.type.should.equal(&#x27;text/html&#x27;);
    res.charset.should.equal(&#x27;utf-8&#x27;);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.set(field, val)</h1>
          <dl>
            <dt>should set the header field</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)
  .set(&#x27;X-Bar&#x27;, &#x27;baz&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);
      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.set(obj)</h1>
          <dl>
            <dt>should set the header fields</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .set({ &#x27;X-Foo&#x27;: &#x27;bar&#x27;, &#x27;X-Bar&#x27;: &#x27;baz&#x27; })
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;bar&#x27;, res.header[&#x27;x-foo&#x27;]);
      assert.equal(&#x27;baz&#x27;, res.header[&#x27;x-bar&#x27;]);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.type(str)</h1>
          <dl>
            <dt>should set the Content-Type</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;text/x-foo&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/x-foo&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should map &#x22;json&#x22;</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;json&#x27;)
  .send(&#x27;{&#x22;a&#x22;: 1}&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.should.be.json();
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should map &#x22;html&#x22;</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;html&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.header[&#x27;content-type&#x27;].should.equal(&#x27;text/html&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.accept(str)</h1>
          <dl>
            <dt>should set Accept</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/echo&#x60;)
  .accept(&#x27;text/x-foo&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.header.accept.should.equal(&#x27;text/x-foo&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should map &#x22;json&#x22;</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/echo&#x60;)
  .accept(&#x27;json&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.header.accept.should.equal(&#x27;application/json&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should map &#x22;xml&#x22;</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/echo&#x60;)
  .accept(&#x27;xml&#x27;)
  .end((error, res) =&#x3E; {
    try {
      // Mime module keeps changing this :(
      assert(
        res.header.accept == &#x27;application/xml&#x27; ||
          res.header.accept == &#x27;text/xml&#x27;
      );
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should map &#x22;html&#x22;</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/echo&#x60;)
  .accept(&#x27;html&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.header.accept.should.equal(&#x27;text/html&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.send(str)</h1>
          <dl>
            <dt>should write the string</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;json&#x27;)
  .send(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;)
  .end((error, res) =&#x3E; {
    try {
      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.send(Object)</h1>
          <dl>
            <dt>should default to json</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error, res) =&#x3E; {
    try {
      res.should.be.json();
      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <section class="suite">
              <h1>when called several times</h1>
              <dl>
                <dt>should merge the objects</dt>
                <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .send({ age: 1 })
  .end((error, res) =&#x3E; {
    try {
      res.should.be.json();
      if (NODE) {
        res.buffered.should.be.true();
      }
      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
              </dl>
            </section>
          </dl>
        </section>
        <section class="suite">
          <h1>.end(fn)</h1>
          <dl>
            <dt>should check arity</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error, res) =&#x3E; {
    try {
      assert.ifError(error);
      res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should emit request</dt>
            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;);
request_.on(&#x27;request&#x27;, (request) =&#x3E; {
  assert.equal(request_, request);
  done();
});
request_.end();</code></pre></dd>
            <dt>should emit response</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .on(&#x27;response&#x27;, (res) =&#x3E; {
    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
    done();
  })
  .end();</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>.then(fulfill, reject)</h1>
          <dl>
            <dt>should support successful fulfills with .then(fulfill)</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return done();
}
request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .then((res) =&#x3E; {
    res.type.should.equal(&#x27;application/json&#x27;);
    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
    done();
  });</code></pre></dd>
            <dt>should reject an error with .then(null, reject)</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return done();
}
request.get(&#x60;${uri}/error&#x60;).then(null, (err) =&#x3E; {
  assert.equal(err.status, 500);
  assert.equal(err.response.text, &#x27;boom&#x27;);
  done();
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>.catch(reject)</h1>
          <dl>
            <dt>should reject an error with .catch(reject)</dt>
            <dd><pre><code>if (typeof Promise === &#x27;undefined&#x27;) {
  return done();
}
request.get(&#x60;${uri}/error&#x60;).catch((err) =&#x3E; {
  assert.equal(err.status, 500);
  assert.equal(err.response.text, &#x27;boom&#x27;);
  done();
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>.abort()</h1>
          <dl>
            <dt>should abort the request</dt>
            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);
request_.end((error, res) =&#x3E; {
  try {
    assert(false, &#x27;should not complete the request&#x27;);
  } catch (err) {
    done(err);
  }
});
request_.on(&#x27;error&#x27;, (error) =&#x3E; {
  done(error);
});
request_.on(&#x27;abort&#x27;, done);
setTimeout(() =&#x3E; {
  request_.abort();
}, 500);</code></pre></dd>
            <dt>should abort the promise</dt>
            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);
setTimeout(() =&#x3E; {
  request_.abort();
}, 10);
return request_.then(
  () =&#x3E; {
    assert.fail(&#x27;should not complete the request&#x27;);
  },
  (err) =&#x3E; {
    assert.equal(&#x27;ABORTED&#x27;, err.code);
  }
);</code></pre></dd>
            <dt>should allow chaining .abort() several times</dt>
            <dd><pre><code>const request_ = request.get(&#x60;${uri}/delay/3000&#x60;);
request_.end((error, res) =&#x3E; {
  try {
    assert(false, &#x27;should not complete the request&#x27;);
  } catch (err) {
    done(err);
  }
});
// This also verifies only a single &#x27;done&#x27; event is emitted
request_.on(&#x27;abort&#x27;, done);
setTimeout(() =&#x3E; {
  request_.abort().abort().abort();
}, 1000);</code></pre></dd>
            <dt>should not allow abort then end</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/delay/3000&#x60;)
  .abort()
  .end((error, res) =&#x3E; {
    done(error ? undefined : new Error(&#x27;Expected abort error&#x27;));
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.toJSON()</h1>
          <dl>
            <dt>should describe the request</dt>
            <dd><pre><code>const request_ = request.post(&#x60;${uri}/echo&#x60;).send({ foo: &#x27;baz&#x27; });
request_.end((error, res) =&#x3E; {
  try {
    const json = request_.toJSON();
    assert.equal(&#x27;POST&#x27;, json.method);
    assert(/\/echo$/.test(json.url));
    assert.equal(&#x27;baz&#x27;, json.data.foo);
    done();
  } catch (err) {
    done(err);
  }
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.options()</h1>
          <dl>
            <dt>should allow request body</dt>
            <dd><pre><code>request
  .options(&#x60;${uri}/options/echo/body&#x60;)
  .send({ foo: &#x27;baz&#x27; })
  .end((error, res) =&#x3E; {
    try {
      assert.equal(error, null);
      assert.strictEqual(res.body.foo, &#x27;baz&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>req.sortQuery()</h1>
          <dl>
            <dt>nop with no querystring</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/url&#x60;)
  .sortQuery()
  .end((error, res) =&#x3E; {
    try {
      assert.equal(res.text, &#x27;/url&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should sort the request querystring</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/url&#x60;)
  .query(&#x27;search=Manny&#x27;)
  .query(&#x27;order=desc&#x27;)
  .sortQuery()
  .end((error, res) =&#x3E; {
    try {
      assert.equal(res.text, &#x27;/url?order=desc&#x26;search=Manny&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should allow disabling sorting</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/url&#x60;)
  .query(&#x27;search=Manny&#x27;)
  .query(&#x27;order=desc&#x27;)
  .sortQuery() // take default of true
  .sortQuery(false) // override it in later call
  .end((error, res) =&#x3E; {
    try {
      assert.equal(res.text, &#x27;/url?search=Manny&#x26;order=desc&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should sort the request querystring using customized function</dt>
            <dd><pre><code>request
  .get(&#x60;${uri}/url&#x60;)
  .query(&#x27;name=Nick&#x27;)
  .query(&#x27;search=Manny&#x27;)
  .query(&#x27;order=desc&#x27;)
  .sortQuery((a, b) =&#x3E; a.length - b.length)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(res.text, &#x27;/url?name=Nick&#x26;order=desc&#x26;search=Manny&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
          </dl>
        </section>
      </dl>
    </section>
    <section class="suite">
      <h1>req.set(&#x22;Content-Type&#x22;, contentType)</h1>
      <dl>
        <dt>should work with just the contentType component</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;application/json&#x27;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error) =&#x3E; {
    assert(!error);
    done();
  });</code></pre></dd>
        <dt>should work with the charset component</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;application/json; charset=utf-8&#x27;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error) =&#x3E; {
    assert(!error);
    done();
  });</code></pre></dd>
      </dl>
    </section>
    <section class="suite">
      <h1>req.send(Object) as &#x22;form&#x22;</h1>
      <dl>
        <section class="suite">
          <h1>with req.type() set to form</h1>
          <dl>
            <dt>should send x-www-form-urlencoded data</dt>
            <dd><pre><code>request
  .post(&#x60;${base}/echo&#x60;)
  .type(&#x27;form&#x27;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error, res) =&#x3E; {
    res.header[&#x27;content-type&#x27;].should.equal(
      &#x27;application/x-www-form-urlencoded&#x27;
    );
    res.text.should.equal(&#x27;name=tobi&#x27;);
    done();
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>when called several times</h1>
          <dl>
            <dt>should merge the objects</dt>
            <dd><pre><code>request
  .post(&#x60;${base}/echo&#x60;)
  .type(&#x27;form&#x27;)
  .send({ name: { first: &#x27;tobi&#x27;, last: &#x27;holowaychuk&#x27; } })
  .send({ age: &#x27;1&#x27; })
  .end((error, res) =&#x3E; {
    res.header[&#x27;content-type&#x27;].should.equal(
      &#x27;application/x-www-form-urlencoded&#x27;
    );
    res.text.should.equal(
      &#x27;name%5Bfirst%5D=tobi&#x26;name%5Blast%5D=holowaychuk&#x26;age=1&#x27;
    );
    done();
  });</code></pre></dd>
          </dl>
        </section>
      </dl>
    </section>
    <section class="suite">
      <h1>req.attach</h1>
      <dl>
        <dt>ignores null file</dt>
        <dd><pre><code>request
  .post(&#x27;/echo&#x27;)
  .attach(&#x27;image&#x27;, null)
  .end((error, res) =&#x3E; {
    done();
  });</code></pre></dd>
      </dl>
    </section>
    <section class="suite">
      <h1>req.field</h1>
      <dl>
        <dt>allow bools</dt>
        <dd><pre><code>if (!formDataSupported) {
  return done();
}
request
  .post(&#x60;${base}/formecho&#x60;)
  .field(&#x27;bools&#x27;, true)
  .field(&#x27;strings&#x27;, &#x27;true&#x27;)
  .end((error, res) =&#x3E; {
    assert.ifError(error);
    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });
    done();
  });</code></pre></dd>
        <dt>allow objects</dt>
        <dd><pre><code>if (!formDataSupported) {
  return done();
}
request
  .post(&#x60;${base}/formecho&#x60;)
  .field({ bools: true, strings: &#x27;true&#x27; })
  .end((error, res) =&#x3E; {
    assert.ifError(error);
    assert.deepStrictEqual(res.body, { bools: &#x27;true&#x27;, strings: &#x27;true&#x27; });
    done();
  });</code></pre></dd>
        <dt>works with arrays in objects</dt>
        <dd><pre><code>if (!formDataSupported) {
  return done();
}
request
  .post(&#x60;${base}/formecho&#x60;)
  .field({ numbers: [1, 2, 3] })
  .end((error, res) =&#x3E; {
    assert.ifError(error);
    assert.deepStrictEqual(res.body, { numbers: [&#x27;1&#x27;, &#x27;2&#x27;, &#x27;3&#x27;] });
    done();
  });</code></pre></dd>
        <dt>works with arrays</dt>
        <dd><pre><code>if (!formDataSupported) {
  return done();
}
request
  .post(&#x60;${base}/formecho&#x60;)
  .field(&#x27;letters&#x27;, [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;])
  .end((error, res) =&#x3E; {
    assert.ifError(error);
    assert.deepStrictEqual(res.body, { letters: [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;] });
    done();
  });</code></pre></dd>
        <dt>throw when empty</dt>
        <dd><pre><code>should.throws(() =&#x3E; {
  request.post(&#x60;${base}/echo&#x60;).field();
}, /name/);
should.throws(() =&#x3E; {
  request.post(&#x60;${base}/echo&#x60;).field(&#x27;name&#x27;);
}, /val/);</code></pre></dd>
        <dt>cannot be mixed with send()</dt>
        <dd><pre><code>assert.throws(() =&#x3E; {
  request.post(&#x27;/echo&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;).send(&#x27;hi&#x27;);
});
assert.throws(() =&#x3E; {
  request.post(&#x27;/echo&#x27;).send(&#x27;hi&#x27;).field(&#x27;form&#x27;, &#x27;data&#x27;);
});</code></pre></dd>
      </dl>
    </section>
    <section class="suite">
      <h1>req.send(Object) as &#x22;json&#x22;</h1>
      <dl>
        <dt>should default to json</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .end((error, res) =&#x3E; {
    res.should.be.json();
    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;}&#x27;);
    done();
  });</code></pre></dd>
        <dt>should work with arrays</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send([1, 2, 3])
  .end((error, res) =&#x3E; {
    res.should.be.json();
    res.text.should.equal(&#x27;[1,2,3]&#x27;);
    done();
  });</code></pre></dd>
        <dt>should work with value null</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;json&#x27;)
  .send(&#x27;null&#x27;)
  .end((error, res) =&#x3E; {
    res.should.be.json();
    assert.strictEqual(res.body, null);
    done();
  });</code></pre></dd>
        <dt>should work with value false</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;json&#x27;)
  .send(&#x27;false&#x27;)
  .end((error, res) =&#x3E; {
    res.should.be.json();
    res.body.should.equal(false);
    done();
  });</code></pre></dd>
        <dt>should work with empty string value</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .type(&#x27;json&#x27;)
  .send(&#x27;&#x22;&#x22;&#x27;)
  .end((error, res) =&#x3E; {
    res.should.be.json();
    res.body.should.equal(&#x27;&#x27;);
    done();
  });</code></pre></dd>
        <dt>should work with vendor MIME type</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;application/vnd.example+json&#x27;)
  .send({ name: &#x27;vendor&#x27; })
  .end((error, res) =&#x3E; {
    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;vendor&#x22;}&#x27;);
    ({ name: &#x27;vendor&#x27; }.should.eql(res.body));
    done();
  });</code></pre></dd>
        <section class="suite">
          <h1>when called several times</h1>
          <dl>
            <dt>should merge the objects</dt>
            <dd><pre><code>request
  .post(&#x60;${uri}/echo&#x60;)
  .send({ name: &#x27;tobi&#x27; })
  .send({ age: 1 })
  .end((error, res) =&#x3E; {
    res.should.be.json();
    res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;tobi&#x22;,&#x22;age&#x22;:1}&#x27;);
    ({ name: &#x27;tobi&#x27;, age: 1 }.should.eql(res.body));
    done();
  });</code></pre></dd>
          </dl>
        </section>
      </dl>
    </section>
    <section class="suite">
      <h1>res.body</h1>
      <dl>
        <section class="suite">
          <h1>application/json</h1>
          <dl>
            <dt>should parse the body</dt>
            <dd><pre><code>request.get(&#x60;${uri}/json&#x60;).end((error, res) =&#x3E; {
  res.text.should.equal(&#x27;{&#x22;name&#x22;:&#x22;manny&#x22;}&#x27;);
  res.body.should.eql({ name: &#x27;manny&#x27; });
  done();
});</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>Invalid JSON response</h1>
          <dl>
            <dt>should return the raw response</dt>
            <dd><pre><code>request.get(&#x60;${uri}/invalid-json&#x60;).end((error, res) =&#x3E; {
  assert.deepEqual(
    error.rawResponse,
    &#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;
  );
  done();
});</code></pre></dd>
            <dt>should return the http status code</dt>
            <dd><pre><code>request.get(&#x60;${uri}/invalid-json-forbidden&#x60;).end((error, res) =&#x3E; {
  assert.equal(error.statusCode, 403);
  done();
});</code></pre></dd>
          </dl>
        </section>
      </dl>
    </section>
    <section class="suite">
      <h1>request</h1>
      <dl>
        <section class="suite">
          <h1>on redirect</h1>
          <dl>
            <dt>should retain header fields</dt>
            <dd><pre><code>request
  .get(&#x60;${base}/header&#x60;)
  .set(&#x27;X-Foo&#x27;, &#x27;bar&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert(res.body);
      res.body.should.have.property(&#x27;x-foo&#x27;, &#x27;bar&#x27;);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should preserve timeout across redirects</dt>
            <dd><pre><code>request
  .get(&#x60;${base}/movies/random&#x60;)
  .timeout(250)
  .end((error, res) =&#x3E; {
    try {
      assert(error instanceof Error, &#x27;expected an error&#x27;);
      error.should.have.property(&#x27;timeout&#x27;, 250);
      done();
    } catch (err) {
      done(err);
    }
  });</code></pre></dd>
            <dt>should successfully redirect after retry on error</dt>
            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();
request
  .get(&#x60;${base}/error/redirect/${id}&#x60;)
  .retry(2)
  .end((error, res) =&#x3E; {
    assert(res.ok, &#x27;response should be ok&#x27;);
    assert(res.text, &#x27;first movie page&#x27;);
    done();
  });</code></pre></dd>
            <dt>should preserve retries across redirects</dt>
            <dd><pre><code>const id = Math.random() * 1_000_000 * Date.now();
request
  .get(&#x60;${base}/error/redirect-error${id}&#x60;)
  .retry(2)
  .end((error, res) =&#x3E; {
    assert(error, &#x27;expected an error&#x27;);
    assert.equal(2, error.retries, &#x27;expected an error with .retries&#x27;);
    assert.equal(500, error.status, &#x27;expected an error status of 500&#x27;);
    done();
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>on 303</h1>
          <dl>
            <dt>should redirect with same method</dt>
            <dd><pre><code>request
  .put(&#x60;${base}/redirect-303&#x60;)
  .send({ msg: &#x27;hello&#x27; })
  .redirects(1)
  .on(&#x27;redirect&#x27;, (res) =&#x3E; {
    res.headers.location.should.equal(&#x27;/reply-method&#x27;);
  })
  .end((error, res) =&#x3E; {
    if (error) {
      done(error);
      return;
    }
    res.text.should.equal(&#x27;method=get&#x27;);
    done();
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>on 307</h1>
          <dl>
            <dt>should redirect with same method</dt>
            <dd><pre><code>if (isMSIE) return done(); // IE9 broken
request
  .put(&#x60;${base}/redirect-307&#x60;)
  .send({ msg: &#x27;hello&#x27; })
  .redirects(1)
  .on(&#x27;redirect&#x27;, (res) =&#x3E; {
    res.headers.location.should.equal(&#x27;/reply-method&#x27;);
  })
  .end((error, res) =&#x3E; {
    if (error) {
      done(error);
      return;
    }
    res.text.should.equal(&#x27;method=put&#x27;);
    done();
  });</code></pre></dd>
          </dl>
        </section>
        <section class="suite">
          <h1>on 308</h1>
          <dl>
            <dt>should redirect with same method</dt>
            <dd><pre><code>if (isMSIE) return done(); // IE9 broken
request
  .put(&#x60;${base}/redirect-308&#x60;)
  .send({ msg: &#x27;hello&#x27; })
  .redirects(1)
  .on(&#x27;redirect&#x27;, (res) =&#x3E; {
    res.headers.location.should.equal(&#x27;/reply-method&#x27;);
  })
  .end((error, res) =&#x3E; {
    if (error) {
      done(error);
      return;
    }
    res.text.should.equal(&#x27;method=put&#x27;);
    done();
  });</code></pre></dd>
          </dl>
        </section>
      </dl>
    </section>
    <section class="suite">
      <h1>request</h1>
      <dl>
        <dt>Request inheritance</dt>
        <dd><pre><code>assert(request.get(&#x60;${uri}/&#x60;) instanceof request.Request);</code></pre></dd>
        <dt>request() simple GET without callback</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x27;test/test.request.js&#x27;).end();
next();</code></pre></dd>
        <dt>request() simple GET</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {
  try {
    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);
    assert(res.ok, &#x27;response should be ok&#x27;);
    assert(res.text, &#x27;res.text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() simple HEAD</dt>
        <dd><pre><code>request.head(&#x60;${uri}/ok&#x60;).end((error, res) =&#x3E; {
  try {
    assert(res instanceof request.Response, &#x27;respond with Response&#x27;);
    assert(res.ok, &#x27;response should be ok&#x27;);
    assert(!res.text, &#x27;res.text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 5xx</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/error&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert.equal(error.message, &#x27;Internal Server Error&#x27;);
    assert(!res.ok, &#x27;response should not be ok&#x27;);
    assert(res.error, &#x27;response should be an error&#x27;);
    assert(!res.clientError, &#x27;response should not be a client error&#x27;);
    assert(res.serverError, &#x27;response should be a server error&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 4xx</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert.equal(error.message, &#x27;Not Found&#x27;);
    assert(!res.ok, &#x27;response should not be ok&#x27;);
    assert(res.error, &#x27;response should be an error&#x27;);
    assert(res.clientError, &#x27;response should be a client error&#x27;);
    assert(!res.serverError, &#x27;response should not be a server error&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 404 Not Found</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert(res.notFound, &#x27;response should be .notFound&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 400 Bad Request</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/bad-request&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert(res.badRequest, &#x27;response should be .badRequest&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 401 Bad Request</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/unauthorized&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert(res.unauthorized, &#x27;response should be .unauthorized&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 406 Not Acceptable</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/not-acceptable&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert(res.notAcceptable, &#x27;response should be .notAcceptable&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() GET 204 No Content</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {
  try {
    assert.ifError(error);
    assert(res.noContent, &#x27;response should be .noContent&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() DELETE 204 No Content</dt>
        <dd><pre><code>request(&#x27;DELETE&#x27;, &#x60;${uri}/no-content&#x60;).end((error, res) =&#x3E; {
  try {
    assert.ifError(error);
    assert(res.noContent, &#x27;response should be .noContent&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() header parsing</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert.equal(&#x27;text/html; charset=utf-8&#x27;, res.header[&#x27;content-type&#x27;]);
    assert.equal(&#x27;Express&#x27;, res.header[&#x27;x-powered-by&#x27;]);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>request() .status</dt>
        <dd><pre><code>request(&#x27;GET&#x27;, &#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert.equal(404, res.status, &#x27;response .status&#x27;);
    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>get()</dt>
        <dd><pre><code>request.get(&#x60;${uri}/notfound&#x60;).end((error, res) =&#x3E; {
  try {
    assert(error);
    assert.equal(404, res.status, &#x27;response .status&#x27;);
    assert.equal(4, res.statusType, &#x27;response .statusType&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>put()</dt>
        <dd><pre><code>request.put(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(&#x27;updated&#x27;, res.text, &#x27;response text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>put().send()</dt>
        <dd><pre><code>request
  .put(&#x60;${uri}/user/13/body&#x60;)
  .send({ user: &#x27;new&#x27; })
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;received new&#x27;, res.text, &#x27;response text&#x27;);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>post()</dt>
        <dd><pre><code>request.post(&#x60;${uri}/user&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(&#x27;created&#x27;, res.text, &#x27;response text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>del()</dt>
        <dd><pre><code>request.del(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>delete()</dt>
        <dd><pre><code>request.delete(&#x60;${uri}/user/12&#x60;).end((error, res) =&#x3E; {
  try {
    assert.equal(&#x27;deleted&#x27;, res.text, &#x27;response text&#x27;);
    next();
  } catch (err) {
    next(err);
  }
});</code></pre></dd>
        <dt>post() data</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/todo/item&#x60;)
  .type(&#x27;application/octet-stream&#x27;)
  .send(&#x27;tobi&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;added &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .type()</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/user/12/pet&#x60;)
  .type(&#x27;urlencoded&#x27;)
  .send(&#x27;pet=tobi&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .type() with alias</dt>
        <dd><pre><code>request
  .post(&#x60;${uri}/user/12/pet&#x60;)
  .type(&#x27;application/x-www-form-urlencoded&#x27;)
  .send(&#x27;pet=tobi&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;added pet &#x22;tobi&#x22;&#x27;, res.text, &#x27;response text&#x27;);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .get() with no data or callback</dt>
        <dd><pre><code>request.get(&#x60;${uri}/echo-header/content-type&#x60;);
next();</code></pre></dd>
        <dt>request .send() with no data only</dt>
        <dd><pre><code>request.post(&#x60;${uri}/user/5/pet&#x60;).type(&#x27;urlencoded&#x27;).send(&#x27;pet=tobi&#x27;);
next();</code></pre></dd>
        <dt>request .send() with callback only</dt>
        <dd><pre><code>request
  .get(&#x60;${uri}/echo-header/accept&#x60;)
  .set(&#x27;Accept&#x27;, &#x27;foo/bar&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;foo/bar&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .accept() with json</dt>
        <dd><pre><code>request
  .get(&#x60;${uri}/echo-header/accept&#x60;)
  .accept(&#x27;json&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;application/json&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .accept() with application/json</dt>
        <dd><pre><code>request
  .get(&#x60;${uri}/echo-header/accept&#x60;)
  .accept(&#x27;application/json&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;application/json&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .accept() with xml</dt>
        <dd><pre><code>request
  .get(&#x60;${uri}/echo-header/accept&#x60;)
  .accept(&#x27;xml&#x27;)
  .end((error, res) =&#x3E; {
    try {
      // We can&#x27;t depend on mime module to be consistent with this
      assert(res.text == &#x27;application/xml&#x27; || res.text == &#x27;text/xml&#x27;);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .accept() with application/xml</dt>
        <dd><pre><code>request
  .get(&#x60;${uri}/echo-header/accept&#x60;)
  .accept(&#x27;application/xml&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;application/xml&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .end()</dt>
        <dd><pre><code>request
  .put(&#x60;${uri}/echo-header/content-type&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)
  .send(&#x27;wahoo&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;text/plain&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .send()</dt>
        <dd><pre><code>request
  .put(&#x60;${uri}/echo-header/content-type&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)
  .send(&#x27;wahoo&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;text/plain&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .set()</dt>
        <dd><pre><code>request
  .put(&#x60;${uri}/echo-header/content-type&#x60;)
  .set(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)
  .send(&#x27;wahoo&#x27;)
  .end((error, res) =&#x3E; {
    try {
      assert.equal(&#x27;text/plain&#x27;, res.text);
      next();
    } catch (err) {
      next(err);
    }
  });</code></pre></dd>
        <dt>request .set(object)</dt>
        <dd><pre><code>request
  .put(&#x60;${uri}/echo-header/content-type&#x60;)
  .set({ &#x27;Content-Type&#x27;: &#x27;text/plain&#x27; })
  .send(&#x27;wahoo&#x27;)
  .end
Download .txt
gitextract_wy1qkpbs/

├── .browserslistrc
├── .commitlintrc.js
├── .dist.babelrc
├── .dist.eslintrc
├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .lib.babelrc
├── .lib.eslintrc
├── .lintstagedrc.js
├── .npmrc
├── .prettierrc.js
├── .remarkignore
├── .remarkrc.js
├── .test.babelrc
├── .travis.yml
├── .xo-config.js
├── .zuul.yml
├── CONTRIBUTING.md
├── HISTORY.md
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── ci/
│   └── remove-deps-4-old-node.js
├── docs/
│   ├── head.html
│   ├── index.md
│   ├── ko_KR/
│   │   ├── index.html
│   │   └── index.md
│   ├── style.css
│   ├── tail.html
│   ├── test.html
│   └── zh_CN/
│       ├── index.html
│       └── index.md
├── examples/
│   └── simple-get.js
├── index.html
├── package.json
├── src/
│   ├── agent-base.js
│   ├── client.js
│   ├── node/
│   │   ├── agent.js
│   │   ├── decompress.js
│   │   ├── http2wrapper.js
│   │   ├── index.js
│   │   ├── parsers/
│   │   │   ├── image.js
│   │   │   ├── index.js
│   │   │   ├── json.js
│   │   │   ├── text.js
│   │   │   └── urlencoded.js
│   │   ├── response.js
│   │   └── unzip.js
│   ├── request-base.js
│   ├── response-base.js
│   └── utils.js
└── test/
    ├── agent-base.js
    ├── basic.js
    ├── client/
    │   ├── request.js
    │   ├── serialize.js
    │   └── xdomain.js
    ├── content-type.js
    ├── form.js
    ├── json.js
    ├── node/
    │   ├── agency.js
    │   ├── basic-auth.js
    │   ├── basic.js
    │   ├── buffers.js
    │   ├── exports.js
    │   ├── fixtures/
    │   │   ├── ca.cert.pem
    │   │   ├── ca.key.pem
    │   │   ├── ca.srl
    │   │   ├── cert.csr
    │   │   ├── cert.pem
    │   │   ├── cert.pfx
    │   │   ├── key.pem
    │   │   ├── passcert.pfx
    │   │   ├── test.aac
    │   │   ├── user.html
    │   │   ├── user.json
    │   │   └── user.txt
    │   ├── flags.js
    │   ├── form.js
    │   ├── http2.js
    │   ├── https.js
    │   ├── image.js
    │   ├── incoming-multipart.js
    │   ├── inflate.js
    │   ├── lookup.js
    │   ├── multipart.js
    │   ├── network-error.js
    │   ├── not-modified.js
    │   ├── parsers.js
    │   ├── pipe-callback.js
    │   ├── pipe-redirect.js
    │   ├── pipe.js
    │   ├── query.js
    │   ├── redirects-other-host.js
    │   ├── redirects.js
    │   ├── response-readable-stream.js
    │   ├── serialize.js
    │   ├── set-host.js
    │   ├── toError.js
    │   ├── unix-sockets.js
    │   ├── user-agent.js
    │   └── utils.js
    ├── redirects.js
    ├── request.js
    ├── retry.js
    ├── support/
    │   ├── blank.js
    │   ├── client.js
    │   ├── express/
    │   │   ├── index.js
    │   │   ├── requestDecorator.js
    │   │   ├── responseDecorator.js
    │   │   └── utils.js
    │   ├── server.js
    │   └── setup.js
    ├── timeout.js
    └── use.js
Download .txt
SYMBOL INDEX (75 symbols across 22 files)

FILE: ci/remove-deps-4-old-node.js
  constant UNSUPPORT_DEPS_4_OLD (line 5) | const UNSUPPORT_DEPS_4_OLD = new Set([

FILE: src/agent-base.js
  class Agent (line 26) | class Agent {
    method constructor (line 27) | constructor () {
    method _setDefaults (line 31) | _setDefaults (request) {

FILE: src/client.js
  function noop (line 32) | function noop() {}
  function serialize (line 88) | function serialize(object) {
  function pushEncodedKeyValuePair (line 107) | function pushEncodedKeyValuePair(pairs, key, value) {
  function parseString (line 142) | function parseString(string_) {
  function parseHeader (line 224) | function parseHeader(string_) {
  function isJSON (line 256) | function isJSON(mime) {
  function Response (line 308) | function Response(request_) {
  function Request (line 407) | function Request(method, url) {
  method apply (line 878) | apply(target, thisArg, argumentsList) {
  function del (line 974) | function del(url, data, fn) {

FILE: src/node/agent.js
  class Agent (line 17) | class Agent extends AgentBase {
    method constructor (line 18) | constructor (options) {
    method _saveCookies (line 53) | _saveCookies (res) {
    method _attachCookies (line 67) | _attachCookies (request_) {
  method apply (line 104) | apply (target, thisArg, argumentsList) {

FILE: src/node/http2wrapper.js
  function setProtocol (line 16) | function setProtocol(protocol) {
  function normalizeIpv6Host (line 24) | function normalizeIpv6Host(host) {
  class Request (line 28) | class Request extends Stream {
    method constructor (line 29) | constructor(protocol, options) {
    method createUnixConnection (line 67) | createUnixConnection(authority, options) {
    method setNoDelay (line 81) | setNoDelay(bool) {
    method getFrame (line 87) | getFrame() {
    method mapToHttpHeader (line 121) | mapToHttpHeader(headers) {
    method mapToHttp2Header (line 141) | mapToHttp2Header(headers) {
    method setHeader (line 164) | setHeader(name, value) {
    method getHeader (line 168) | getHeader(name) {
    method write (line 172) | write(data, encoding) {
    method pipe (line 177) | pipe(stream, options) {
    method end (line 182) | end(data) {
    method abort (line 187) | abort(data) {

FILE: src/node/index.js
  function request (line 30) | function request(method, url) {
  function noop (line 63) | function noop() {}
  function _initHeaders (line 133) | function _initHeaders(request_) {
  function Request (line 150) | function Request(method, url) {
  function isText (line 1373) | function isText(mime) {
  function isBinary (line 1386) | function isBinary(mime) {
  function isJSON (line 1404) | function isJSON(mime) {
  function isRedirect (line 1418) | function isRedirect(code) {
  function hasNonEmptyResponseContent (line 1422) | function hasNonEmptyResponseContent(res) {

FILE: src/node/response.js
  function Response (line 30) | function Response(request) {
  method get (line 53) | get() {
  method set (line 60) | set(value) {

FILE: src/request-base.js
  function RequestBase (line 18) | function RequestBase() {}
  constant ERROR_CODES (line 163) | const ERROR_CODES = new Set([
  constant STATUS_CODES (line 174) | const STATUS_CODES = new Set([

FILE: src/response-base.js
  function ResponseBase (line 19) | function ResponseBase() {}

FILE: test/client/request.js
  function testParser (line 218) | function testParser(data) {

FILE: test/client/serialize.js
  function serialize (line 5) | function serialize(object, res) {
  function parse (line 16) | function parse(string_, object) {

FILE: test/node/lookup.js
  function myLookup (line 9) | function myLookup(hostname, options, callback) {

FILE: test/node/multipart.js
  constant IS_WINDOWS (line 10) | const IS_WINDOWS = require('os').platform() === 'win32';
  function read (line 12) | function read(file) {
  function getFullPath (line 16) | function getFullPath(filename) {

FILE: test/node/network-error.js
  function getFreePort (line 7) | function getFreePort(fn) {

FILE: test/retry.js
  function uniqid (line 6) | function uniqid() {
  function retryCallback (line 272) | function retryCallback(request) {

FILE: test/support/express/index.js
  function createApp (line 16) | function createApp() {

FILE: test/support/express/requestDecorator.js
  function setMethods (line 36) | function setMethods(request) {
  function defineGetter (line 496) | function defineGetter(object, name, getter) {

FILE: test/support/express/responseDecorator.js
  function setMethods (line 42) | function setMethods(res) {
  function stringify (line 993) | function stringify(value, replacer, spaces, escape) {

FILE: test/support/express/utils.js
  function acceptParameters (line 98) | function acceptParameters(string_, index) {
  function createETagGenerator (line 257) | function createETagGenerator(options) {
  function parseExtendedQueryString (line 272) | function parseExtendedQueryString(string_) {

FILE: test/support/server.js
  function serveImageWithType (line 500) | function serveImageWithType(res, type) {

FILE: test/support/setup.js
  constant NODE (line 6) | let NODE;
  function getSetup (line 9) | async function getSetup() {

FILE: test/use.js
  function uuid (line 19) | function uuid(request_) {
  function prefix (line 24) | function prefix(request_) {
  function NewRequest (line 61) | function NewRequest(...args) {
  function NewRequest (line 84) | function NewRequest(...args) {
Condensed preview — 120 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (934K chars).
[
  {
    "path": ".browserslistrc",
    "chars": 20,
    "preview": "defaults, not ie 11\n"
  },
  {
    "path": ".commitlintrc.js",
    "chars": 69,
    "preview": "module.exports = {\n  extends: ['@commitlint/config-conventional']\n};\n"
  },
  {
    "path": ".dist.babelrc",
    "chars": 197,
    "preview": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"browsers\": [ \"defaults, not ie 11\" ]\n      }\n    }]\n  "
  },
  {
    "path": ".dist.eslintrc",
    "chars": 994,
    "preview": "{\n  \"extends\": [\"eslint:recommended\", \"plugin:compat/recommended\"],\n  \"env\": {\n    \"node\": false,\n    \"browser\": true,\n "
  },
  {
    "path": ".editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
  },
  {
    "path": ".eslintrc",
    "chars": 754,
    "preview": "{\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:node/recommended\"\n  ],\n  \"env\": {\n    \"node\": true,\n    \"browser\""
  },
  {
    "path": ".gitattributes",
    "chars": 12,
    "preview": "* text=auto\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1300,
    "preview": "name: CI\non: [push, pull_request]\n\nenv:\n  SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}\n  SAUCE_ACCESS_KEY: ${{ secrets."
  },
  {
    "path": ".gitignore",
    "chars": 185,
    "preview": ".vscode\nbuild\nlib-cov\ncoverage.html\n.DS_Store\nnode_modules\n*.sock\ntest.js\ncomponents\ntest/node/fixtures/tmp.json\n.idea\ns"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 25,
    "preview": "npx commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 16,
    "preview": "npx lint-staged\n"
  },
  {
    "path": ".lib.babelrc",
    "chars": 177,
    "preview": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"node\": \"14.18.0\",\n        \"browsers\": [ \"defaults, not"
  },
  {
    "path": ".lib.eslintrc",
    "chars": 885,
    "preview": "{\n  \"extends\": [\"eslint:recommended\", \"plugin:node/recommended\"],\n  \"env\": {\n    \"browser\": true\n  },\n  \"rules\": {\n    \""
  },
  {
    "path": ".lintstagedrc.js",
    "chars": 120,
    "preview": "module.exports = {\n  \"*.md\": filenames => filenames.map(filename => `remark ${filename} -qfo`),\n  '*.js': 'xo --fix'\n};\n"
  },
  {
    "path": ".npmrc",
    "chars": 18,
    "preview": "package-lock=true\n"
  },
  {
    "path": ".prettierrc.js",
    "chars": 91,
    "preview": "module.exports = {\n  singleQuote: true,\n  bracketSpacing: true,\n  trailingComma: 'none'\n};\n"
  },
  {
    "path": ".remarkignore",
    "chars": 32,
    "preview": "CONTRIBUTING.md\nHISTORY.md\ndocs\n"
  },
  {
    "path": ".remarkrc.js",
    "chars": 51,
    "preview": "module.exports = {\n  plugins: ['preset-github']\n};\n"
  },
  {
    "path": ".test.babelrc",
    "chars": 292,
    "preview": "{\n  \"presets\": [\n    [\"@babel/env\", {\n      \"targets\": {\n        \"node\": \"14.18.0\",\n        \"browsers\": [ \"defaults, not"
  },
  {
    "path": ".travis.yml",
    "chars": 219,
    "preview": "sudo: false\nlanguage: node_js\nnode_js:\n  - '18'\n  - '16'\n  - '14'\nafter_success: npm run coverage\n\nenv:\n  global:\n    - "
  },
  {
    "path": ".xo-config.js",
    "chars": 2185,
    "preview": "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"
  },
  {
    "path": ".zuul.yml",
    "chars": 324,
    "preview": "ui: mocha-bdd\nserver: ./test/support/server.js\ntunnel_host: http://focusaurus.com\nbrowsers:\n  - name: chrome\n    version"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 358,
    "preview": "When submitting a PR, your chance of acceptance increases if you do the following:\n\n* Code style is consistent with exis"
  },
  {
    "path": "HISTORY.md",
    "chars": 24720,
    "preview": "# This HISTORY log is deprecated\n\nPlease see [GitHub releases page](https://github.com/ladjs/superagent/releases) for th"
  },
  {
    "path": "LICENSE",
    "chars": 1103,
    "preview": "(The MIT License)\n\nCopyright (c) 2014-2016 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of ch"
  },
  {
    "path": "Makefile",
    "chars": 1811,
    "preview": "OLDNODETESTS ?= lib/node/test/*.js lib/node/test/node/*.js\nNODETESTS ?= test/*.js test/node/*.js\nBROWSERTESTS ?= test/*."
  },
  {
    "path": "README.md",
    "chars": 10605,
    "preview": "# superagent\n\n[![build status](https://github.com/forwardemail/superagent/actions/workflows/ci.yml/badge.svg)](https://g"
  },
  {
    "path": "SECURITY.md",
    "chars": 108,
    "preview": "# 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",
    "chars": 620,
    "preview": "const fs = require('fs');\nconst path = require('path');\nconst package = require('../package.json');\n\nconst UNSUPPORT_DEP"
  },
  {
    "path": "docs/head.html",
    "chars": 346,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and brows"
  },
  {
    "path": "docs/index.md",
    "chars": 31550,
    "preview": "\n# SuperAgent\n\nSuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning "
  },
  {
    "path": "docs/ko_KR/index.html",
    "chars": 42316,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\" />\n    <title>SuperAgent — elegant API for AJAX in Node and bro"
  },
  {
    "path": "docs/ko_KR/index.md",
    "chars": 24764,
    "preview": "# SuperAgent\n\nSuperAgent는 기존의 복잡한 요청 API에 대한 불만에서 출발해 유연성, 가독성, 그리고 낮은 학습 난이도를 목표로 설계된 경량 Ajax API입니다. 또한 Node.js 환경에서도 "
  },
  {
    "path": "docs/style.css",
    "chars": 1457,
    "preview": "body {\n  padding: 40px 80px;\n  font: 14px/1.5 \"Helvetica Neue\", Helvetica, sans-serif;\n  background: #181818 url(images/"
  },
  {
    "path": "docs/tail.html",
    "chars": 1583,
    "preview": "    </div>\n    <a href=\"http://github.com/ladjs/superagent\"><img style=\"position: absolute; top: 0; right: 0; border: 0;"
  },
  {
    "path": "docs/test.html",
    "chars": 302799,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and brows"
  },
  {
    "path": "docs/zh_CN/index.html",
    "chars": 30088,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and brows"
  },
  {
    "path": "docs/zh_CN/index.md",
    "chars": 20733,
    "preview": "# SuperAgent\n\nSuperAgent是轻量级的渐进式ajax API,具有灵活性、可读性和较低的学习曲线。 它也适用于Node.js!  \n\n     request\n       .post('/api/pet')\n     "
  },
  {
    "path": "examples/simple-get.js",
    "chars": 298,
    "preview": "/**\n * Module dependencies.\n */\n\nconst request = require('..');\n\nconst url =\n  'https://gist.githubusercontent.com/reina"
  },
  {
    "path": "index.html",
    "chars": 42963,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf8\">\n    <title>SuperAgent — elegant API for AJAX in Node and brows"
  },
  {
    "path": "package.json",
    "chars": 3865,
    "preview": "{\n  \"name\": \"superagent\",\n  \"description\": \"elegant & feature rich browser / node HTTP with a fluent API\",\n  \"version\": "
  },
  {
    "path": "src/agent-base.js",
    "chars": 674,
    "preview": "const defaults = [\n  'use',\n  'on',\n  'once',\n  'set',\n  'query',\n  'type',\n  'accept',\n  'auth',\n  'withCredentials',\n "
  },
  {
    "path": "src/client.js",
    "chars": 23508,
    "preview": "/**\n * Root reference for iframes.\n */\n\nlet root;\nif (typeof window !== 'undefined') {\n  // Browser window\n  root = wind"
  },
  {
    "path": "src/node/agent.js",
    "chars": 2428,
    "preview": "/**\n * Module dependencies.\n */\n\nconst { CookieJar } = require('cookiejar');\nconst { CookieAccessInfo } = require('cooki"
  },
  {
    "path": "src/node/decompress.js",
    "chars": 441,
    "preview": "const zlib = require('zlib');\nconst utils = require('../utils');\nconst { isGzipOrDeflateEncoding, isBrotliEncoding } = u"
  },
  {
    "path": "src/node/http2wrapper.js",
    "chars": 4615,
    "preview": "const http2 = require('http2');\nconst Stream = require('stream');\nconst net = require('net');\nconst tls = require('tls')"
  },
  {
    "path": "src/node/index.js",
    "chars": 35325,
    "preview": "/**\n * Module dependencies.\n */\n\nconst { format } = require('url');\nconst Stream = require('stream');\nconst https = requ"
  },
  {
    "path": "src/node/parsers/image.js",
    "chars": 214,
    "preview": "module.exports = (res, fn) => {\n  const data = []; // Binary data needs binary storage\n\n  res.on('data', (chunk) => {\n  "
  },
  {
    "path": "src/node/parsers/index.js",
    "chars": 348,
    "preview": "exports['application/x-www-form-urlencoded'] = require('./urlencoded');\nexports['application/json'] = require('./json');"
  },
  {
    "path": "src/node/parsers/json.js",
    "chars": 583,
    "preview": "module.exports = function (res, fn) {\n  res.text = '';\n  res.setEncoding('utf8');\n  res.on('data', (chunk) => {\n    res."
  },
  {
    "path": "src/node/parsers/text.js",
    "chars": 159,
    "preview": "module.exports = (res, fn) => {\n  res.text = '';\n  res.setEncoding('utf8');\n  res.on('data', (chunk) => {\n    res.text +"
  },
  {
    "path": "src/node/parsers/urlencoded.js",
    "chars": 316,
    "preview": "/**\n * Module dependencies.\n */\n\nconst qs = require('qs');\n\nmodule.exports = (res, fn) => {\n  res.text = '';\n  res.setEn"
  },
  {
    "path": "src/node/response.js",
    "chars": 2749,
    "preview": "/**\n * Module dependencies.\n */\n\nconst util = require('util');\nconst Stream = require('stream');\nconst ResponseBase = re"
  },
  {
    "path": "src/node/unzip.js",
    "chars": 1629,
    "preview": "/**\n * Module dependencies.\n */\n\nconst { StringDecoder } = require('string_decoder');\nconst Stream = require('stream');\n"
  },
  {
    "path": "src/request-base.js",
    "chars": 18393,
    "preview": "/**\n * Module of mixed-in functions shared between node and client code\n */\nconst { isObject, hasOwn } = require('./util"
  },
  {
    "path": "src/response-base.js",
    "chars": 2624,
    "preview": "/**\n * Module dependencies.\n */\n\nconst utils = require('./utils');\n\n/**\n * Expose `ResponseBase`.\n */\n\nmodule.exports = "
  },
  {
    "path": "src/utils.js",
    "chars": 2737,
    "preview": "\n/**\n * Return the mime type for the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexp"
  },
  {
    "path": "test/agent-base.js",
    "chars": 1201,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  },
  {
    "path": "test/basic.js",
    "chars": 19037,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  },
  {
    "path": "test/client/request.js",
    "chars": 8323,
    "preview": "const assert = require('assert');\nconst request = require('../support/client');\n\ndescribe('request', function () {\n  thi"
  },
  {
    "path": "test/client/serialize.js",
    "chars": 2372,
    "preview": "const assert = require('assert');\n\nconst request = require('../support/client');\n\nfunction serialize(object, res) {\n  co"
  },
  {
    "path": "test/client/xdomain.js",
    "chars": 1567,
    "preview": "const assert = require('assert');\nconst request = require('../support/client');\n\ndescribe('xdomain', function () {\n  thi"
  },
  {
    "path": "test/content-type.js",
    "chars": 859,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  },
  {
    "path": "test/form.js",
    "chars": 3726,
    "preview": "const assert = require('assert');\nconst should = require('should');\n\nconst getSetup = require('./support/setup');\nconst "
  },
  {
    "path": "test/json.js",
    "chars": 7418,
    "preview": "const getSetup = require('./support/setup');\n\nconst doesntWorkInHttp2 = !process.env.HTTP2_TEST;\n\nconst assert = require"
  },
  {
    "path": "test/node/agency.js",
    "chars": 6132,
    "preview": "'use strict';\n\nconst express = require('../support/express');\n\nconst app = express();\nconst request = require('../suppor"
  },
  {
    "path": "test/node/basic-auth.js",
    "chars": 1279,
    "preview": "const assert = require('assert');\nconst { format } = require('url');\nconst request = require('../support/client');\nconst"
  },
  {
    "path": "test/node/basic.js",
    "chars": 9813,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst { EventEmitter } = require('events');\nc"
  },
  {
    "path": "test/node/buffers.js",
    "chars": 3253,
    "preview": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('"
  },
  {
    "path": "test/node/exports.js",
    "chars": 765,
    "preview": "'use strict';\nconst request = require('../support/client');\n\ndescribe('exports', () => {\n  it('should expose .protocols'"
  },
  {
    "path": "test/node/fixtures/ca.cert.pem",
    "chars": 956,
    "preview": "-----BEGIN CERTIFICATE-----\nMIICljCCAX4CCQDnGz3+qH/zGzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJD\nQTAeFw0xODEyMDIxNjIyMThaFw0"
  },
  {
    "path": "test/node/fixtures/ca.key.pem",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAtgUDcB7R94A22I0D8Ibac000ZBINtvnyvoPP5U2hRsxI9tcW\n/LLm0GhzM5XJJNQ0jSv0ixI"
  },
  {
    "path": "test/node/fixtures/ca.srl",
    "chars": 17,
    "preview": "B23299143E26EFC5\n"
  },
  {
    "path": "test/node/fixtures/cert.csr",
    "chars": 891,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgK"
  },
  {
    "path": "test/node/fixtures/cert.pem",
    "chars": 969,
    "preview": "-----BEGIN CERTIFICATE-----\nMIICnTCCAYUCCQCyMpkUPibvxTANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJD\nQTAeFw0xODEyMDIxNjIzNTBaFw0"
  },
  {
    "path": "test/node/fixtures/key.pem",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsjNYMUk1HzBLM4fL/8c6Z86X/b13V1bMXrrcV28wjmvQv4lA\nDlghZGt/zbinyvZrASp8v1b"
  },
  {
    "path": "test/node/fixtures/user.html",
    "chars": 13,
    "preview": "<h1>name</h1>"
  },
  {
    "path": "test/node/fixtures/user.json",
    "chars": 15,
    "preview": "{\"name\":\"tobi\"}"
  },
  {
    "path": "test/node/fixtures/user.txt",
    "chars": 4,
    "preview": "Tobi"
  },
  {
    "path": "test/node/flags.js",
    "chars": 3363,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require("
  },
  {
    "path": "test/node/form.js",
    "chars": 1515,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require("
  },
  {
    "path": "test/node/http2.js",
    "chars": 894,
    "preview": "'use strict';\nif (!process.env.HTTP2_TEST) {\n  return;\n}\n\nconst assert = require('assert');\nconst request = require('../"
  },
  {
    "path": "test/node/https.js",
    "chars": 7020,
    "preview": "'use strict';\n\nconst assert = require('assert');\n\nconst https = require('https');\nconst fs = require('fs');\nconst expres"
  },
  {
    "path": "test/node/image.js",
    "chars": 1546,
    "preview": "'use strict';\n\nconst fs = require('fs');\nconst request = require('../support/client');\nconst getSetup = require('../supp"
  },
  {
    "path": "test/node/incoming-multipart.js",
    "chars": 1674,
    "preview": "// var request = require('../support/client')\n//   , express = require('express')\n//   , assert = require('assert')\n//  "
  },
  {
    "path": "test/node/inflate.js",
    "chars": 6422,
    "preview": "'use strict';\nrequire('should');\nrequire('should-http');\n\nconst assert = require('assert');\nconst zlib = require('zlib')"
  },
  {
    "path": "test/node/lookup.js",
    "chars": 633,
    "preview": "'use strict';\nconst assert = require('assert');\nconst dns = require('dns');\nconst request = require('../support/client')"
  },
  {
    "path": "test/node/multipart.js",
    "chars": 7970,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\nconst should = "
  },
  {
    "path": "test/node/network-error.js",
    "chars": 764,
    "preview": "'use strict';\nconst assert = require('assert');\nconst net = require('net');\nconst request = require('../support/client')"
  },
  {
    "path": "test/node/not-modified.js",
    "chars": 839,
    "preview": "'use strict';\nconst request = require('../support/client');\nconst getSetup = require('../support/setup');\n\ndescribe('req"
  },
  {
    "path": "test/node/parsers.js",
    "chars": 2118,
    "preview": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('"
  },
  {
    "path": "test/node/pipe-callback.js",
    "chars": 1198,
    "preview": "const assert = require('node:assert');\nconst { Readable } = require('node:stream');\nconst getSetup = require('../support"
  },
  {
    "path": "test/node/pipe-redirect.js",
    "chars": 996,
    "preview": "'use strict';\nconst fs = require('fs');\nconst request = require('../support/client');\nconst getSetup = require('../suppo"
  },
  {
    "path": "test/node/pipe.js",
    "chars": 5510,
    "preview": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = "
  },
  {
    "path": "test/node/query.js",
    "chars": 5805,
    "preview": "'use strict';\nlet http = require('http');\nconst assert = require('assert');\nconst fs = require('fs');\nconst request = re"
  },
  {
    "path": "test/node/redirects-other-host.js",
    "chars": 6379,
    "preview": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst express = require('."
  },
  {
    "path": "test/node/redirects.js",
    "chars": 10090,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst getSetup = require('../support/setup');\nconst request = require('"
  },
  {
    "path": "test/node/response-readable-stream.js",
    "chars": 1433,
    "preview": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = "
  },
  {
    "path": "test/node/serialize.js",
    "chars": 640,
    "preview": "'use strict';\n\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require("
  },
  {
    "path": "test/node/set-host.js",
    "chars": 1134,
    "preview": "'use strict';\nconst request = require('../support/client');\nconst express = require('../support/express');\n\nconst app = "
  },
  {
    "path": "test/node/toError.js",
    "chars": 965,
    "preview": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst express = require('."
  },
  {
    "path": "test/node/unix-sockets.js",
    "chars": 3050,
    "preview": "'use strict';\nconst assert = require('assert');\n\nlet http = require('http');\nlet https = require('https');\nconst os = re"
  },
  {
    "path": "test/node/user-agent.js",
    "chars": 457,
    "preview": "'use strict';\nconst assert = require('assert');\nconst request = require('../support/client');\nconst getSetup = require('"
  },
  {
    "path": "test/node/utils.js",
    "chars": 4606,
    "preview": "'use strict';\nconst assert = require('assert');\nconst utils =\n  process.env.OLD_NODE_TEST === '1'\n    ? // eslint-disabl"
  },
  {
    "path": "test/redirects.js",
    "chars": 3632,
    "preview": "const assert = require('assert');\n\nconst getSetup = require('./support/setup');\nconst request = require('./support/clien"
  },
  {
    "path": "test/request.js",
    "chars": 23491,
    "preview": "const fs = require('fs');\n\nconst assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request"
  },
  {
    "path": "test/retry.js",
    "chars": 7719,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  },
  {
    "path": "test/support/blank.js",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/support/client.js",
    "chars": 128,
    "preview": "const request = require('../..');\n\nif (process.env.HTTP2_TEST) {\n  request.http2 = true;\n}\n\nexports = module.exports = r"
  },
  {
    "path": "test/support/express/index.js",
    "chars": 857,
    "preview": "const process = require('process');\nconst express = require('express');\n\nlet http2Request;\nlet http2Res;\nif (process.env"
  },
  {
    "path": "test/support/express/requestDecorator.js",
    "chars": 12412,
    "preview": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2013 Roman Shtylman\n * Copyright(c) 2014-2015 Do"
  },
  {
    "path": "test/support/express/responseDecorator.js",
    "chars": 24687,
    "preview": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Lice"
  },
  {
    "path": "test/support/express/utils.js",
    "chars": 5168,
    "preview": "/*!\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Lice"
  },
  {
    "path": "test/support/server.js",
    "chars": 14337,
    "preview": "const fs = require('node:fs');\nconst path = require('node:path');\nconst process = require('node:process');\nconst { Buffe"
  },
  {
    "path": "test/support/setup.js",
    "chars": 690,
    "preview": "require('should');\nrequire('should-http');\n\nconst getPort = require('get-port');\n\nlet NODE;\nlet uri;\n\nasync function get"
  },
  {
    "path": "test/timeout.js",
    "chars": 3967,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  },
  {
    "path": "test/use.js",
    "chars": 2296,
    "preview": "const assert = require('assert');\nconst getSetup = require('./support/setup');\n\nconst request = require('./support/clien"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the forwardemail/superagent GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 120 files (874.3 KB), approximately 272.8k tokens, and a symbol index with 75 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!