From 585e23d8d2926876480ff1df426f76bcc3430fc7 Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Fri, 4 Oct 2024 15:03:11 -0700 Subject: [PATCH] Use modern JS features, ship TS defs --- .eslintignore | 2 - .eslintrc.yml | 11 - .github/workflows/ci.yml | 261 +- .gitignore | 3 +- README.md | 251 +- benchmark/index.js | 34 - benchmark/parse-top.js | 37 - benchmark/parse.js | 74 - index.js | 335 -- package-lock.json | 4585 +++++++++++++++++++++++++ package.json | 58 +- {benchmark => scripts}/parse-top.json | 0 scripts/update-benchmark.js | 111 +- src/index.ts | 386 +++ src/parse.bench.ts | 47 + src/parse.spec.ts | 96 + src/serialize.spec.ts | 338 ++ test/parse.js | 85 - test/serialize.js | 319 -- tsconfig.build.json | 4 + tsconfig.json | 9 + 21 files changed, 5677 insertions(+), 1369 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.yml delete mode 100644 benchmark/index.js delete mode 100644 benchmark/parse-top.js delete mode 100644 benchmark/parse.js delete mode 100644 index.js create mode 100644 package-lock.json rename {benchmark => scripts}/parse-top.json (100%) create mode 100644 src/index.ts create mode 100644 src/parse.bench.ts create mode 100644 src/parse.spec.ts create mode 100644 src/serialize.spec.ts delete mode 100644 test/parse.js delete mode 100644 test/serialize.js create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 62562b7..0000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -coverage -node_modules diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index 44febf6..0000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,11 +0,0 @@ -extends: - - plugin:markdown/recommended -plugins: - - markdown -overrides: - - files: '**/*.md' - processor: 'markdown/markdown' -rules: - eol-last: error - indent: ["error", 2, { "SwitchCase": 1 }] - no-trailing-spaces: error diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9da9752..6194883 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,253 +1,26 @@ name: ci on: -- pull_request -- push + - pull_request + - push jobs: test: - runs-on: ubuntu-20.04 + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest strategy: matrix: - name: - - Node.js 0.6 - - Node.js 0.8 - - Node.js 0.10 - - Node.js 0.12 - - io.js 1.x - - io.js 2.x - - io.js 3.x - - Node.js 4.x - - Node.js 5.x - - Node.js 6.x - - Node.js 7.x - - Node.js 8.x - - Node.js 9.x - - Node.js 10.x - - Node.js 11.x - - Node.js 12.x - - Node.js 13.x - - Node.js 14.x - - Node.js 15.x - - Node.js 16.x - - Node.js 17.x - - Node.js 18.x - - Node.js 19.x - - Node.js 20.x - - Node.js 21.x - - include: - - name: Node.js 0.6 - node-version: "0.6" - npm-i: mocha@1.21.5 - npm-rm: beautify-benchmark benchmark nyc top-sites - - - name: Node.js 0.8 - node-version: "0.8" - npm-i: mocha@2.5.3 - npm-rm: beautify-benchmark benchmark nyc top-sites - - - name: Node.js 0.10 - node-version: "0.10" - npm-i: mocha@3.5.3 nyc@10.3.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 0.12 - node-version: "0.12" - npm-i: mocha@3.5.3 nyc@10.3.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: io.js 1.x - node-version: "1.8" - npm-i: mocha@3.5.3 nyc@10.3.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: io.js 2.x - node-version: "2.5" - npm-i: mocha@3.5.3 nyc@10.3.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: io.js 3.x - node-version: "3.3" - npm-i: mocha@3.5.3 nyc@10.3.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 4.x - node-version: "4.9" - npm-i: mocha@5.2.0 nyc@11.9.0 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 5.x - node-version: "5.12" - npm-i: mocha@5.2.0 nyc@11.9.0 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 6.x - node-version: "6.17" - npm-i: mocha@6.2.2 nyc@14.1.1 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 7.x - node-version: "7.10" - npm-i: mocha@6.2.2 nyc@14.1.1 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 8.x - node-version: "8.17" - npm-i: mocha@7.1.2 nyc@14.1.1 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 9.x - node-version: "9.11" - npm-i: mocha@7.1.2 nyc@14.1.1 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 10.x - node-version: "10.24" - npm-i: mocha@8.4.0 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 11.x - node-version: "11.15" - npm-i: mocha@8.4.0 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 12.x - node-version: "12.22" - npm-i: mocha@9.2.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 13.x - node-version: "13.14" - npm-i: mocha@9.2.2 - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 14.x - node-version: "14.21" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 15.x - node-version: "15.14" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 16.x - node-version: "16.20" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 17.x - node-version: "17.9" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 18.x - node-version: "18.18" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 19.x - node-version: "19.9" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 20.x - node-version: "20.9" - npm-rm: beautify-benchmark benchmark top-sites - - - name: Node.js 21.x - node-version: "21.1" - - steps: - - uses: actions/checkout@v3 - - - name: Install Node.js ${{ matrix.node-version }} - shell: bash -eo pipefail -l {0} - run: | - if [[ "${{ matrix.node-version }}" == 0.6* ]]; then - sudo sh -c 'echo "deb http://us.archive.ubuntu.com/ubuntu/ bionic universe" >> /etc/apt/sources.list' - sudo sh -c 'echo "deb http://security.ubuntu.com/ubuntu bionic-security main" >> /etc/apt/sources.list' - sudo apt-get update - sudo apt-get install g++-4.8 gcc-4.8 libssl1.0-dev python2 python-is-python2 - export CC=/usr/bin/gcc-4.8 - export CXX=/usr/bin/g++-4.8 - fi - nvm install --default ${{ matrix.node-version }} - if [[ "${{ matrix.node-version }}" == 0.* && "$(cut -d. -f2 <<< "${{ matrix.node-version }}")" -lt 10 ]]; then - nvm install --alias=npm 0.10 - nvm use ${{ matrix.node-version }} - if [[ "$(npm -v)" == 1.1.* ]]; then - nvm exec npm npm install -g npm@1.1 - ln -fs "$(which npm)" "$(dirname "$(nvm which npm)")/npm" - else - sed -i '1s;^.*$;'"$(printf '#!%q' "$(nvm which npm)")"';' "$(readlink -f "$(which npm)")" - fi - npm config set strict-ssl false - fi - dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH" - - - name: Configure npm - run: | - if [[ "$(npm config get package-lock)" == "true" ]]; then - npm config set package-lock false - else - npm config set shrinkwrap false - fi - - - name: Remove npm module(s) ${{ matrix.npm-rm }} - run: npm rm --silent --save-dev ${{ matrix.npm-rm }} - if: matrix.npm-rm != '' - - - name: Install npm module(s) ${{ matrix.npm-i }} - run: npm install --save-dev ${{ matrix.npm-i }} - if: matrix.npm-i != '' - - - name: Setup Node.js version-specific dependencies - shell: bash - run: | - # eslint for linting - # - remove on Node.js < 12 - if [[ "$(cut -d. -f1 <<< "${{ matrix.node-version }}")" -lt 12 ]]; then - node -pe 'Object.keys(require("./package").devDependencies).join("\n")' | \ - grep -E '^eslint(-|$)' | \ - sort -r | \ - xargs -n1 npm rm --silent --save-dev - fi - - - name: Install Node.js dependencies - run: npm install - - - name: List environment - id: list_env - shell: bash - run: | - echo "node@$(node -v)" - echo "npm@$(npm -v)" - npm -s ls ||: - (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT" - - - name: Run tests - shell: bash - run: | - if npm -ps ls nyc | grep -q nyc; then - npm run test-ci - else - npm test - fi - - - name: Lint code - if: steps.list_env.outputs.eslint != '' - run: npm run lint - - - name: Collect code coverage - uses: coverallsapp/github-action@master - if: steps.list_env.outputs.nyc != '' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - flag-name: run-${{ matrix.test_number }} - parallel: true - - coverage: - needs: test - runs-on: ubuntu-latest + node-version: + - "18" + - "20" + - "22" steps: - - name: Upload code coverage - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.github_token }} - parallel-finished: true + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm test + - uses: codecov/codecov-action@v4 + with: + name: Node.js ${{ matrix.node-version }} diff --git a/.gitignore b/.gitignore index f15b98e..74b68ed 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ coverage/ node_modules/ npm-debug.log -package-lock.json +dist/ +*.tsbuildinfo diff --git a/README.md b/README.md index 71fdac1..40fbc76 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,6 @@ Basic HTTP cookie parser and serializer for HTTP servers. ## Installation -This is a [Node.js](https://nodejs.org/en/) module available through the -[npm registry](https://www.npmjs.com/). Installation is done using the -[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): - ```sh $ npm install cookie ``` @@ -21,7 +17,7 @@ $ npm install cookie ## API ```js -var cookie = require('cookie'); +const cookie = require("cookie"); ``` ### cookie.parse(str, options) @@ -31,7 +27,7 @@ The `str` argument is the string representing a `Cookie` header value and `optio optional object containing additional parsing options. ```js -var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2'); +const cookies = cookie.parse("foo=bar; equation=E%3Dmc%5E2"); // { foo: 'bar', equation: 'E=mc^2' } ``` @@ -43,12 +39,12 @@ var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2'); Specifies a function that will be used to decode a cookie's value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode -a previously-encoded cookie value into a JavaScript string or other object. +a previously-encoded cookie value into a JavaScript string. The default function is the global `decodeURIComponent`, which will decode any URL-encoded sequences into their byte representations. -**note** if an error is thrown from this function, the original, non-decoded cookie value will +If an error is thrown from this function, the original, non-decoded cookie value will be returned as the cookie's value. ### cookie.serialize(name, value, options) @@ -58,7 +54,7 @@ name for the cookie, the `value` argument is the value to set the cookie to, and argument is an optional object containing additional serialization options. ```js -var setCookie = cookie.serialize('foo', 'bar'); +const setCookie = cookie.serialize("foo", "bar"); // foo=bar ``` @@ -66,11 +62,6 @@ var setCookie = cookie.serialize('foo', 'bar'); `cookie.serialize` accepts these properties in the options object. -##### domain - -Specifies the value for the [`Domain` `Set-Cookie` attribute][rfc-6265-5.2.3]. By default, no -domain is set, and most clients will consider the cookie to apply to only the current domain. - ##### encode Specifies a function that will be used to encode a cookie's value. Since value of a cookie @@ -80,86 +71,83 @@ a value into a string suited for a cookie's value. The default function is the global `encodeURIComponent`, which will encode a JavaScript string into UTF-8 byte sequences and then URL-encode any that fall outside of the cookie range. +##### maxAge + +Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.2). +The given number will be converted to an integer by rounding down. By default, no maximum age is set. + +The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and +`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this, +so if both are set, they should point to the same date and time. + ##### expires -Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute][rfc-6265-5.2.1]. +Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.1). By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application. -**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and +The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this, so if both are set, they should point to the same date and time. +##### domain + +Specifies the value for the [`Domain` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.3). +By default, no domain is set, and most clients will consider the cookie to apply to only the current domain. + +##### path + +Specifies the value for the [`Path` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.4). By default, the path +is considered the ["default path"](https://tools.ietf.org/html/rfc6265#section-5.1.4). + ##### httpOnly -Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute][rfc-6265-5.2.6]. When truthy, +Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.6). When truthy, the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` attribute is not set. -**note** be careful when setting this to `true`, as compliant clients will not allow client-side +Be careful when setting this to `true`, as compliant clients will not allow client-side JavaScript to see the cookie in `document.cookie`. -##### maxAge +##### secure -Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute][rfc-6265-5.2.2]. -The given number will be converted to an integer by rounding down. By default, no maximum age is set. +Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.5). When truthy, +the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set. -**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and -`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this, -so if both are set, they should point to the same date and time. +Be careful when setting this to `true`, as compliant clients will not send the cookie back to +the server in the future if the browser does not have an HTTPS connection. ##### partitioned -Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies) +Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/) attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the `Partitioned` attribute is not set. -**note** This is an attribute that has not yet been fully standardized, and may change in the future. -This also means many clients may ignore this attribute until they understand it. - -More information about can be found in [the proposal](https://github.com/privacycg/CHIPS). - -##### path - -Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path -is considered the ["default path"][rfc-6265-5.1.4]. +This is an attribute that has not yet been fully standardized, and may change in the future. +This also means many clients may ignore this attribute until they understand it. More information +about can be found in [the proposal](https://github.com/privacycg/CHIPS). ##### priority -Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1]. +Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1). - - `'low'` will set the `Priority` attribute to `Low`. - - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set. - - `'high'` will set the `Priority` attribute to `High`. +- `'low'` will set the `Priority` attribute to `Low`. +- `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set. +- `'high'` will set the `Priority` attribute to `High`. More information about the different priority levels can be found in -[the specification][rfc-west-cookie-priority-00-4.1]. - -**note** This is an attribute that has not yet been fully standardized, and may change in the future. -This also means many clients may ignore this attribute until they understand it. +[the specification](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1). ##### sameSite -Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.7]. +Specifies the value for the [`SameSite` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7). - - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. - - `false` will not set the `SameSite` attribute. - - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement. - - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie. - - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement. +- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. +- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement. +- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie. +- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement. More information about the different enforcement levels can be found in -[the specification][rfc-6265bis-09-5.4.7]. - -**note** This is an attribute that has not yet been fully standardized, and may change in the future. -This also means many clients may ignore this attribute until they understand it. - -##### secure - -Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute][rfc-6265-5.2.5]. When truthy, -the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set. - -**note** be careful when setting this to `true`, as compliant clients will not send the cookie back to -the server in the future if the browser does not have an HTTPS connection. +[the specification](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7). ## Example @@ -167,10 +155,10 @@ The following example uses this module in conjunction with the Node.js core HTTP to prompt a user for their name and display it back on future visits. ```js -var cookie = require('cookie'); -var escapeHtml = require('escape-html'); -var http = require('http'); -var url = require('url'); +var cookie = require("cookie"); +var escapeHtml = require("escape-html"); +var http = require("http"); +var url = require("url"); function onRequest(req, res) { // Parse the query string @@ -178,35 +166,40 @@ function onRequest(req, res) { if (query && query.name) { // Set a new cookie with the name - res.setHeader('Set-Cookie', cookie.serialize('name', String(query.name), { - httpOnly: true, - maxAge: 60 * 60 * 24 * 7 // 1 week - })); + res.setHeader( + "Set-Cookie", + cookie.serialize("name", String(query.name), { + httpOnly: true, + maxAge: 60 * 60 * 24 * 7, // 1 week + }), + ); // Redirect back after setting cookie res.statusCode = 302; - res.setHeader('Location', req.headers.referer || '/'); + res.setHeader("Location", req.headers.referer || "/"); res.end(); return; } // Parse the cookies on the request - var cookies = cookie.parse(req.headers.cookie || ''); + var cookies = cookie.parse(req.headers.cookie || ""); // Get the visitor name set in the cookie var name = cookies.name; - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.setHeader("Content-Type", "text/html; charset=UTF-8"); if (name) { - res.write('

Welcome back, ' + escapeHtml(name) + '!

'); + res.write("

Welcome back, " + escapeHtml(name) + "!

"); } else { - res.write('

Hello, new visitor!

'); + res.write("

Hello, new visitor!

"); } res.write('
'); - res.write(' '); - res.end('
'); + res.write( + ' ', + ); + res.end(""); } http.createServer(onRequest).listen(3000); @@ -215,92 +208,46 @@ http.createServer(onRequest).listen(3000); ## Testing ```sh -$ npm test +npm test ``` ## Benchmark +```sh +npm run bench +``` + ``` -$ npm run bench - -> cookie@0.5.0 bench -> node benchmark/index.js - - node@18.18.2 - acorn@8.10.0 - ada@2.6.0 - ares@1.19.1 - brotli@1.0.9 - cldr@43.1 - icu@73.2 - llhttp@6.0.11 - modules@108 - napi@9 - nghttp2@1.57.0 - nghttp3@0.7.0 - ngtcp2@0.8.1 - openssl@3.0.10+quic - simdutf@3.2.14 - tz@2023c - undici@5.26.3 - unicode@15.0 - uv@1.44.2 - uvwasi@0.0.18 - v8@10.2.154.26-node.26 - zlib@1.2.13.1-motley - -> node benchmark/parse-top.js - - cookie.parse - top sites - - 14 tests completed. - - parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled) - parse apple.com x 2,370,002 ops/sec ±0.69% (186 runs sampled) - parse cloudflare.com x 2,213,102 ops/sec ±0.88% (188 runs sampled) - parse docs.google.com x 2,194,157 ops/sec ±1.03% (184 runs sampled) - parse drive.google.com x 2,265,084 ops/sec ±0.79% (187 runs sampled) - parse en.wikipedia.org x 457,099 ops/sec ±0.81% (186 runs sampled) - parse linkedin.com x 504,407 ops/sec ±0.89% (186 runs sampled) - parse maps.google.com x 1,230,959 ops/sec ±0.98% (186 runs sampled) - parse microsoft.com x 926,294 ops/sec ±0.88% (184 runs sampled) - parse play.google.com x 2,311,338 ops/sec ±0.83% (185 runs sampled) - parse support.google.com x 1,508,850 ops/sec ±0.86% (186 runs sampled) - parse www.google.com x 1,022,582 ops/sec ±1.32% (182 runs sampled) - parse youtu.be x 332,136 ops/sec ±1.02% (185 runs sampled) - parse youtube.com x 323,833 ops/sec ±0.77% (183 runs sampled) - -> node benchmark/parse.js - - cookie.parse - generic - - 6 tests completed. - - simple x 3,214,032 ops/sec ±1.61% (183 runs sampled) - decode x 587,237 ops/sec ±1.16% (187 runs sampled) - unquote x 2,954,618 ops/sec ±1.35% (183 runs sampled) - duplicates x 857,008 ops/sec ±0.89% (187 runs sampled) - 10 cookies x 292,133 ops/sec ±0.89% (187 runs sampled) - 100 cookies x 22,610 ops/sec ±0.68% (187 runs sampled) + name hz min max mean p75 p99 p995 p999 rme samples + · simple 8,566,313.09 0.0000 0.3694 0.0001 0.0001 0.0002 0.0002 0.0003 ±0.64% 4283157 fastest + · decode 3,834,348.85 0.0001 0.2465 0.0003 0.0003 0.0003 0.0004 0.0006 ±0.38% 1917175 + · unquote 8,315,355.96 0.0000 0.3824 0.0001 0.0001 0.0002 0.0002 0.0003 ±0.72% 4157880 + · duplicates 1,944,765.97 0.0004 0.2959 0.0005 0.0005 0.0006 0.0006 0.0008 ±0.24% 972384 + · 10 cookies 675,345.67 0.0012 0.4328 0.0015 0.0015 0.0019 0.0020 0.0058 ±0.75% 337673 + · 100 cookies 61,040.71 0.0152 0.4092 0.0164 0.0160 0.0196 0.0228 0.2260 ±0.71% 30521 slowest + ✓ parse top-sites (15) 22945ms + name hz min max mean p75 p99 p995 p999 rme samples + · parse accounts.google.com 7,164,349.17 0.0000 0.0929 0.0001 0.0002 0.0002 0.0002 0.0003 ±0.09% 3582184 + · parse apple.com 7,817,686.84 0.0000 0.6048 0.0001 0.0001 0.0002 0.0002 0.0003 ±1.05% 3908844 + · parse cloudflare.com 7,189,841.70 0.0000 0.0390 0.0001 0.0002 0.0002 0.0002 0.0003 ±0.06% 3594921 + · parse docs.google.com 7,051,765.61 0.0000 0.0296 0.0001 0.0002 0.0002 0.0002 0.0003 ±0.06% 3525883 + · parse drive.google.com 7,349,104.77 0.0000 0.0368 0.0001 0.0001 0.0002 0.0002 0.0003 ±0.05% 3674553 + · parse en.wikipedia.org 1,929,909.49 0.0004 0.3598 0.0005 0.0005 0.0007 0.0007 0.0012 ±0.16% 964955 + · parse linkedin.com 2,225,658.01 0.0003 0.0595 0.0004 0.0005 0.0005 0.0005 0.0006 ±0.06% 1112830 + · parse maps.google.com 4,423,511.68 0.0001 0.0942 0.0002 0.0003 0.0003 0.0003 0.0005 ±0.08% 2211756 + · parse microsoft.com 3,387,601.88 0.0002 0.0725 0.0003 0.0003 0.0004 0.0004 0.0005 ±0.09% 1693801 + · parse play.google.com 7,375,980.86 0.0000 0.1994 0.0001 0.0001 0.0002 0.0002 0.0003 ±0.12% 3687991 + · parse support.google.com 4,912,267.94 0.0001 2.8958 0.0002 0.0002 0.0003 0.0003 0.0005 ±1.28% 2456134 + · parse www.google.com 3,443,035.87 0.0002 0.2783 0.0003 0.0003 0.0004 0.0004 0.0007 ±0.51% 1721518 + · parse youtu.be 1,910,492.87 0.0004 0.3490 0.0005 0.0005 0.0007 0.0007 0.0011 ±0.46% 955247 + · parse youtube.com 1,895,082.62 0.0004 0.7454 0.0005 0.0005 0.0006 0.0007 0.0013 ±0.64% 947542 slowest + · parse example.com 21,582,835.27 0.0000 0.1095 0.0000 0.0000 0.0001 0.0001 0.0001 ±0.13% 10791418 ``` ## References -- [RFC 6265: HTTP State Management Mechanism][rfc-6265] -- [Same-site Cookies][rfc-6265bis-09-5.4.7] - -[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/ -[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1 -[rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7 -[rfc-6265]: https://tools.ietf.org/html/rfc6265 -[rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4 -[rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1 -[rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2 -[rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3 -[rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4 -[rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5 -[rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6 -[rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3 +- [RFC 6265: HTTP State Management Mechanism](https://tools.ietf.org/html/rfc6265) +- [Same-site Cookies](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7) ## License diff --git a/benchmark/index.js b/benchmark/index.js deleted file mode 100644 index 8a39f3a..0000000 --- a/benchmark/index.js +++ /dev/null @@ -1,34 +0,0 @@ -var fs = require('fs') -var path = require('path') -var spawn = require('child_process').spawn - -var exe = process.argv[0] -var cwd = process.cwd() - -for (var dep in process.versions) { - console.log(' %s@%s', dep, process.versions[dep]) -} - -console.log('') - -runScripts(fs.readdirSync(__dirname)) - -function runScripts (fileNames) { - var fileName = fileNames.shift() - - if (!fileName) return - if (!/\.js$/i.test(fileName)) return runScripts(fileNames) - if (fileName.toLowerCase() === 'index.js') return runScripts(fileNames) - - var fullPath = path.join(__dirname, fileName) - - console.log('> %s %s', exe, path.relative(cwd, fullPath)) - - var proc = spawn(exe, [fullPath], { - 'stdio': 'inherit' - }) - - proc.on('exit', function () { - runScripts(fileNames) - }) -} diff --git a/benchmark/parse-top.js b/benchmark/parse-top.js deleted file mode 100644 index 4cbfd00..0000000 --- a/benchmark/parse-top.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Module dependencies. - */ - -var benchmark = require('benchmark') -var benchmarks = require('beautify-benchmark') -var top = require('./parse-top.json') - -/** - * Globals for benchmark.js - */ - -global.cookie = require('..') - -var suite = new benchmark.Suite() - -Object.keys(top).forEach(function (domain) { - suite.add({ - name: 'parse ' + domain, - minSamples: 100, - fn: 'var val = cookie.parse(' + JSON.stringify(top[domain]) + ')' - }) -}) - -suite.on('start', function () { - process.stdout.write(' cookie.parse - top sites\n\n') -}) - -suite.on('cycle', function (event) { - benchmarks.add(event.target) -}) - -suite.on('complete', function () { - benchmarks.log() -}) - -suite.run({ async: false }) diff --git a/benchmark/parse.js b/benchmark/parse.js deleted file mode 100644 index 567f4b6..0000000 --- a/benchmark/parse.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Module dependencies. - */ - -var benchmark = require('benchmark') -var benchmarks = require('beautify-benchmark') - -/** - * Globals for benchmark.js - */ - -global.cookie = require('..') - -var suite = new benchmark.Suite() - -suite.add({ - name: 'simple', - minSamples: 100, - fn: 'var val = cookie.parse("foo=bar")' -}) - -suite.add({ - name: 'decode', - minSamples: 100, - fn: 'var val = cookie.parse("foo=hello%20there!")' -}) - -suite.add({ - name: 'unquote', - minSamples: 100, - fn: 'var val = cookie.parse("foo=\\"foo bar\\"")' -}) - -suite.add({ - name: 'duplicates', - minSamples: 100, - fn: 'var val = cookie.parse(' + JSON.stringify(gencookies(2) + '; ' + gencookies(2)) + ')' -}) - -suite.add({ - name: '10 cookies', - minSamples: 100, - fn: 'var val = cookie.parse(' + JSON.stringify(gencookies(10)) + ')' -}) - -suite.add({ - name: '100 cookies', - minSamples: 100, - fn: 'var val = cookie.parse(' + JSON.stringify(gencookies(100)) + ')' -}) - -suite.on('start', function () { - process.stdout.write(' cookie.parse - generic\n\n') -}) - -suite.on('cycle', function (event) { - benchmarks.add(event.target) -}) - -suite.on('complete', function onComplete () { - benchmarks.log() -}) - -suite.run({ async: false }) - -function gencookies (num) { - var str = '' - - for (var i = 0; i < num; i++) { - str += '; foo' + i + '=bar' - } - - return str.slice(2) -} diff --git a/index.js b/index.js deleted file mode 100644 index acd5acd..0000000 --- a/index.js +++ /dev/null @@ -1,335 +0,0 @@ -/*! - * cookie - * Copyright(c) 2012-2014 Roman Shtylman - * Copyright(c) 2015 Douglas Christopher Wilson - * MIT Licensed - */ - -'use strict'; - -/** - * Module exports. - * @public - */ - -exports.parse = parse; -exports.serialize = serialize; - -/** - * Module variables. - * @private - */ - -var __toString = Object.prototype.toString -var __hasOwnProperty = Object.prototype.hasOwnProperty - -/** - * RegExp to match cookie-name in RFC 6265 sec 4.1.1 - * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2 - * which has been replaced by the token definition in RFC 7230 appendix B. - * - * cookie-name = token - * token = 1*tchar - * tchar = "!" / "#" / "$" / "%" / "&" / "'" / - * "*" / "+" / "-" / "." / "^" / "_" / - * "`" / "|" / "~" / DIGIT / ALPHA - */ - -var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; - -/** - * RegExp to match cookie-value in RFC 6265 sec 4.1.1 - * - * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) - * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E - * ; US-ASCII characters excluding CTLs, - * ; whitespace DQUOTE, comma, semicolon, - * ; and backslash - */ - -var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; - -/** - * RegExp to match domain-value in RFC 6265 sec 4.1.1 - * - * domain-value = - * ; defined in [RFC1034], Section 3.5, as - * ; enhanced by [RFC1123], Section 2.1 - * =