| 1 | # cookie
|
|---|
| 2 |
|
|---|
| 3 | [![NPM Version][npm-version-image]][npm-url]
|
|---|
| 4 | [![NPM Downloads][npm-downloads-image]][npm-url]
|
|---|
| 5 | [![Node.js Version][node-image]][node-url]
|
|---|
| 6 | [![Build Status][ci-image]][ci-url]
|
|---|
| 7 | [![Coverage Status][coveralls-image]][coveralls-url]
|
|---|
| 8 |
|
|---|
| 9 | Basic HTTP cookie parser and serializer for HTTP servers.
|
|---|
| 10 |
|
|---|
| 11 | ## Installation
|
|---|
| 12 |
|
|---|
| 13 | This is a [Node.js](https://nodejs.org/en/) module available through the
|
|---|
| 14 | [npm registry](https://www.npmjs.com/). Installation is done using the
|
|---|
| 15 | [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
|---|
| 16 |
|
|---|
| 17 | ```sh
|
|---|
| 18 | $ npm install cookie
|
|---|
| 19 | ```
|
|---|
| 20 |
|
|---|
| 21 | ## API
|
|---|
| 22 |
|
|---|
| 23 | ```js
|
|---|
| 24 | var cookie = require('cookie');
|
|---|
| 25 | ```
|
|---|
| 26 |
|
|---|
| 27 | ### cookie.parse(str, options)
|
|---|
| 28 |
|
|---|
| 29 | Parse an HTTP `Cookie` header string and returning an object of all cookie name-value pairs.
|
|---|
| 30 | The `str` argument is the string representing a `Cookie` header value and `options` is an
|
|---|
| 31 | optional object containing additional parsing options.
|
|---|
| 32 |
|
|---|
| 33 | ```js
|
|---|
| 34 | var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2');
|
|---|
| 35 | // { foo: 'bar', equation: 'E=mc^2' }
|
|---|
| 36 | ```
|
|---|
| 37 |
|
|---|
| 38 | #### Options
|
|---|
| 39 |
|
|---|
| 40 | `cookie.parse` accepts these properties in the options object.
|
|---|
| 41 |
|
|---|
| 42 | ##### decode
|
|---|
| 43 |
|
|---|
| 44 | Specifies a function that will be used to decode a cookie's value. Since the value of a cookie
|
|---|
| 45 | has a limited character set (and must be a simple string), this function can be used to decode
|
|---|
| 46 | a previously-encoded cookie value into a JavaScript string or other object.
|
|---|
| 47 |
|
|---|
| 48 | The default function is the global `decodeURIComponent`, which will decode any URL-encoded
|
|---|
| 49 | sequences into their byte representations.
|
|---|
| 50 |
|
|---|
| 51 | **note** if an error is thrown from this function, the original, non-decoded cookie value will
|
|---|
| 52 | be returned as the cookie's value.
|
|---|
| 53 |
|
|---|
| 54 | ### cookie.serialize(name, value, options)
|
|---|
| 55 |
|
|---|
| 56 | Serialize a cookie name-value pair into a `Set-Cookie` header string. The `name` argument is the
|
|---|
| 57 | name for the cookie, the `value` argument is the value to set the cookie to, and the `options`
|
|---|
| 58 | argument is an optional object containing additional serialization options.
|
|---|
| 59 |
|
|---|
| 60 | ```js
|
|---|
| 61 | var setCookie = cookie.serialize('foo', 'bar');
|
|---|
| 62 | // foo=bar
|
|---|
| 63 | ```
|
|---|
| 64 |
|
|---|
| 65 | #### Options
|
|---|
| 66 |
|
|---|
| 67 | `cookie.serialize` accepts these properties in the options object.
|
|---|
| 68 |
|
|---|
| 69 | ##### domain
|
|---|
| 70 |
|
|---|
| 71 | Specifies the value for the [`Domain` `Set-Cookie` attribute][rfc-6265-5.2.3]. By default, no
|
|---|
| 72 | domain is set, and most clients will consider the cookie to apply to only the current domain.
|
|---|
| 73 |
|
|---|
| 74 | ##### encode
|
|---|
| 75 |
|
|---|
| 76 | Specifies a function that will be used to encode a cookie's value. Since value of a cookie
|
|---|
| 77 | has a limited character set (and must be a simple string), this function can be used to encode
|
|---|
| 78 | a value into a string suited for a cookie's value.
|
|---|
| 79 |
|
|---|
| 80 | The default function is the global `encodeURIComponent`, which will encode a JavaScript string
|
|---|
| 81 | into UTF-8 byte sequences and then URL-encode any that fall outside of the cookie range.
|
|---|
| 82 |
|
|---|
| 83 | ##### expires
|
|---|
| 84 |
|
|---|
| 85 | Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute][rfc-6265-5.2.1].
|
|---|
| 86 | By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and
|
|---|
| 87 | will delete it on a condition like exiting a web browser application.
|
|---|
| 88 |
|
|---|
| 89 | **note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
|
|---|
| 90 | `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
|
|---|
| 91 | so if both are set, they should point to the same date and time.
|
|---|
| 92 |
|
|---|
| 93 | ##### httpOnly
|
|---|
| 94 |
|
|---|
| 95 | Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute][rfc-6265-5.2.6]. When truthy,
|
|---|
| 96 | the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` attribute is not set.
|
|---|
| 97 |
|
|---|
| 98 | **note** be careful when setting this to `true`, as compliant clients will not allow client-side
|
|---|
| 99 | JavaScript to see the cookie in `document.cookie`.
|
|---|
| 100 |
|
|---|
| 101 | ##### maxAge
|
|---|
| 102 |
|
|---|
| 103 | Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute][rfc-6265-5.2.2].
|
|---|
| 104 | The given number will be converted to an integer by rounding down. By default, no maximum age is set.
|
|---|
| 105 |
|
|---|
| 106 | **note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
|
|---|
| 107 | `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
|
|---|
| 108 | so if both are set, they should point to the same date and time.
|
|---|
| 109 |
|
|---|
| 110 | ##### partitioned
|
|---|
| 111 |
|
|---|
| 112 | Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
|
|---|
| 113 | attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
|
|---|
| 114 | `Partitioned` attribute is not set.
|
|---|
| 115 |
|
|---|
| 116 | **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
|---|
| 117 | This also means many clients may ignore this attribute until they understand it.
|
|---|
| 118 |
|
|---|
| 119 | More information about can be found in [the proposal](https://github.com/privacycg/CHIPS).
|
|---|
| 120 |
|
|---|
| 121 | ##### path
|
|---|
| 122 |
|
|---|
| 123 | Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path
|
|---|
| 124 | is considered the ["default path"][rfc-6265-5.1.4].
|
|---|
| 125 |
|
|---|
| 126 | ##### priority
|
|---|
| 127 |
|
|---|
| 128 | Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
|
|---|
| 129 |
|
|---|
| 130 | - `'low'` will set the `Priority` attribute to `Low`.
|
|---|
| 131 | - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
|
|---|
| 132 | - `'high'` will set the `Priority` attribute to `High`.
|
|---|
| 133 |
|
|---|
| 134 | More information about the different priority levels can be found in
|
|---|
| 135 | [the specification][rfc-west-cookie-priority-00-4.1].
|
|---|
| 136 |
|
|---|
| 137 | **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
|---|
| 138 | This also means many clients may ignore this attribute until they understand it.
|
|---|
| 139 |
|
|---|
| 140 | ##### sameSite
|
|---|
| 141 |
|
|---|
| 142 | Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.7].
|
|---|
| 143 |
|
|---|
| 144 | - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
|---|
| 145 | - `false` will not set the `SameSite` attribute.
|
|---|
| 146 | - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
|
|---|
| 147 | - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
|
|---|
| 148 | - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
|---|
| 149 |
|
|---|
| 150 | More information about the different enforcement levels can be found in
|
|---|
| 151 | [the specification][rfc-6265bis-09-5.4.7].
|
|---|
| 152 |
|
|---|
| 153 | **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
|---|
| 154 | This also means many clients may ignore this attribute until they understand it.
|
|---|
| 155 |
|
|---|
| 156 | ##### secure
|
|---|
| 157 |
|
|---|
| 158 | Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute][rfc-6265-5.2.5]. When truthy,
|
|---|
| 159 | the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
|
|---|
| 160 |
|
|---|
| 161 | **note** be careful when setting this to `true`, as compliant clients will not send the cookie back to
|
|---|
| 162 | the server in the future if the browser does not have an HTTPS connection.
|
|---|
| 163 |
|
|---|
| 164 | ## Example
|
|---|
| 165 |
|
|---|
| 166 | The following example uses this module in conjunction with the Node.js core HTTP server
|
|---|
| 167 | to prompt a user for their name and display it back on future visits.
|
|---|
| 168 |
|
|---|
| 169 | ```js
|
|---|
| 170 | var cookie = require('cookie');
|
|---|
| 171 | var escapeHtml = require('escape-html');
|
|---|
| 172 | var http = require('http');
|
|---|
| 173 | var url = require('url');
|
|---|
| 174 |
|
|---|
| 175 | function onRequest(req, res) {
|
|---|
| 176 | // Parse the query string
|
|---|
| 177 | var query = url.parse(req.url, true, true).query;
|
|---|
| 178 |
|
|---|
| 179 | if (query && query.name) {
|
|---|
| 180 | // Set a new cookie with the name
|
|---|
| 181 | res.setHeader('Set-Cookie', cookie.serialize('name', String(query.name), {
|
|---|
| 182 | httpOnly: true,
|
|---|
| 183 | maxAge: 60 * 60 * 24 * 7 // 1 week
|
|---|
| 184 | }));
|
|---|
| 185 |
|
|---|
| 186 | // Redirect back after setting cookie
|
|---|
| 187 | res.statusCode = 302;
|
|---|
| 188 | res.setHeader('Location', req.headers.referer || '/');
|
|---|
| 189 | res.end();
|
|---|
| 190 | return;
|
|---|
| 191 | }
|
|---|
| 192 |
|
|---|
| 193 | // Parse the cookies on the request
|
|---|
| 194 | var cookies = cookie.parse(req.headers.cookie || '');
|
|---|
| 195 |
|
|---|
| 196 | // Get the visitor name set in the cookie
|
|---|
| 197 | var name = cookies.name;
|
|---|
| 198 |
|
|---|
| 199 | res.setHeader('Content-Type', 'text/html; charset=UTF-8');
|
|---|
| 200 |
|
|---|
| 201 | if (name) {
|
|---|
| 202 | res.write('<p>Welcome back, <b>' + escapeHtml(name) + '</b>!</p>');
|
|---|
| 203 | } else {
|
|---|
| 204 | res.write('<p>Hello, new visitor!</p>');
|
|---|
| 205 | }
|
|---|
| 206 |
|
|---|
| 207 | res.write('<form method="GET">');
|
|---|
| 208 | res.write('<input placeholder="enter your name" name="name"> <input type="submit" value="Set Name">');
|
|---|
| 209 | res.end('</form>');
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | http.createServer(onRequest).listen(3000);
|
|---|
| 213 | ```
|
|---|
| 214 |
|
|---|
| 215 | ## Testing
|
|---|
| 216 |
|
|---|
| 217 | ```sh
|
|---|
| 218 | $ npm test
|
|---|
| 219 | ```
|
|---|
| 220 |
|
|---|
| 221 | ## Benchmark
|
|---|
| 222 |
|
|---|
| 223 | ```
|
|---|
| 224 | $ npm run bench
|
|---|
| 225 |
|
|---|
| 226 | > cookie@0.5.0 bench
|
|---|
| 227 | > node benchmark/index.js
|
|---|
| 228 |
|
|---|
| 229 | node@18.18.2
|
|---|
| 230 | acorn@8.10.0
|
|---|
| 231 | ada@2.6.0
|
|---|
| 232 | ares@1.19.1
|
|---|
| 233 | brotli@1.0.9
|
|---|
| 234 | cldr@43.1
|
|---|
| 235 | icu@73.2
|
|---|
| 236 | llhttp@6.0.11
|
|---|
| 237 | modules@108
|
|---|
| 238 | napi@9
|
|---|
| 239 | nghttp2@1.57.0
|
|---|
| 240 | nghttp3@0.7.0
|
|---|
| 241 | ngtcp2@0.8.1
|
|---|
| 242 | openssl@3.0.10+quic
|
|---|
| 243 | simdutf@3.2.14
|
|---|
| 244 | tz@2023c
|
|---|
| 245 | undici@5.26.3
|
|---|
| 246 | unicode@15.0
|
|---|
| 247 | uv@1.44.2
|
|---|
| 248 | uvwasi@0.0.18
|
|---|
| 249 | v8@10.2.154.26-node.26
|
|---|
| 250 | zlib@1.2.13.1-motley
|
|---|
| 251 |
|
|---|
| 252 | > node benchmark/parse-top.js
|
|---|
| 253 |
|
|---|
| 254 | cookie.parse - top sites
|
|---|
| 255 |
|
|---|
| 256 | 14 tests completed.
|
|---|
| 257 |
|
|---|
| 258 | parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled)
|
|---|
| 259 | parse apple.com x 2,370,002 ops/sec ±0.69% (186 runs sampled)
|
|---|
| 260 | parse cloudflare.com x 2,213,102 ops/sec ±0.88% (188 runs sampled)
|
|---|
| 261 | parse docs.google.com x 2,194,157 ops/sec ±1.03% (184 runs sampled)
|
|---|
| 262 | parse drive.google.com x 2,265,084 ops/sec ±0.79% (187 runs sampled)
|
|---|
| 263 | parse en.wikipedia.org x 457,099 ops/sec ±0.81% (186 runs sampled)
|
|---|
| 264 | parse linkedin.com x 504,407 ops/sec ±0.89% (186 runs sampled)
|
|---|
| 265 | parse maps.google.com x 1,230,959 ops/sec ±0.98% (186 runs sampled)
|
|---|
| 266 | parse microsoft.com x 926,294 ops/sec ±0.88% (184 runs sampled)
|
|---|
| 267 | parse play.google.com x 2,311,338 ops/sec ±0.83% (185 runs sampled)
|
|---|
| 268 | parse support.google.com x 1,508,850 ops/sec ±0.86% (186 runs sampled)
|
|---|
| 269 | parse www.google.com x 1,022,582 ops/sec ±1.32% (182 runs sampled)
|
|---|
| 270 | parse youtu.be x 332,136 ops/sec ±1.02% (185 runs sampled)
|
|---|
| 271 | parse youtube.com x 323,833 ops/sec ±0.77% (183 runs sampled)
|
|---|
| 272 |
|
|---|
| 273 | > node benchmark/parse.js
|
|---|
| 274 |
|
|---|
| 275 | cookie.parse - generic
|
|---|
| 276 |
|
|---|
| 277 | 6 tests completed.
|
|---|
| 278 |
|
|---|
| 279 | simple x 3,214,032 ops/sec ±1.61% (183 runs sampled)
|
|---|
| 280 | decode x 587,237 ops/sec ±1.16% (187 runs sampled)
|
|---|
| 281 | unquote x 2,954,618 ops/sec ±1.35% (183 runs sampled)
|
|---|
| 282 | duplicates x 857,008 ops/sec ±0.89% (187 runs sampled)
|
|---|
| 283 | 10 cookies x 292,133 ops/sec ±0.89% (187 runs sampled)
|
|---|
| 284 | 100 cookies x 22,610 ops/sec ±0.68% (187 runs sampled)
|
|---|
| 285 | ```
|
|---|
| 286 |
|
|---|
| 287 | ## References
|
|---|
| 288 |
|
|---|
| 289 | - [RFC 6265: HTTP State Management Mechanism][rfc-6265]
|
|---|
| 290 | - [Same-site Cookies][rfc-6265bis-09-5.4.7]
|
|---|
| 291 |
|
|---|
| 292 | [rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/
|
|---|
| 293 | [rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1
|
|---|
| 294 | [rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7
|
|---|
| 295 | [rfc-6265]: https://tools.ietf.org/html/rfc6265
|
|---|
| 296 | [rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4
|
|---|
| 297 | [rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1
|
|---|
| 298 | [rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2
|
|---|
| 299 | [rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3
|
|---|
| 300 | [rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4
|
|---|
| 301 | [rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5
|
|---|
| 302 | [rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6
|
|---|
| 303 | [rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3
|
|---|
| 304 |
|
|---|
| 305 | ## License
|
|---|
| 306 |
|
|---|
| 307 | [MIT](LICENSE)
|
|---|
| 308 |
|
|---|
| 309 | [ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci
|
|---|
| 310 | [ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
|
|---|
| 311 | [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master
|
|---|
| 312 | [coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
|
|---|
| 313 | [node-image]: https://badgen.net/npm/node/cookie
|
|---|
| 314 | [node-url]: https://nodejs.org/en/download
|
|---|
| 315 | [npm-downloads-image]: https://badgen.net/npm/dm/cookie
|
|---|
| 316 | [npm-url]: https://npmjs.org/package/cookie
|
|---|
| 317 | [npm-version-image]: https://badgen.net/npm/v/cookie
|
|---|