diff --git a/.eslintrc.yml b/.eslintrc.yml index 754db18..44febf6 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,3 +1,10 @@ +extends: + - plugin:markdown/recommended +plugins: + - markdown +overrides: + - files: '**/*.md' + processor: 'markdown/markdown' rules: eol-last: error indent: ["error", 2, { "SwitchCase": 1 }] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9da9752 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,253 @@ +name: ci + +on: +- pull_request +- push + +jobs: + test: + runs-on: ubuntu-20.04 + 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 + steps: + - name: Upload code coverage + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.github_token }} + parallel-finished: true diff --git a/.gitignore b/.gitignore index 0fa6951..f15b98e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.nyc_output/ coverage/ node_modules/ npm-debug.log diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 063cec6..0000000 --- a/.travis.yml +++ /dev/null @@ -1,111 +0,0 @@ -language: node_js -node_js: - - "0.6" - - "0.8" - - "0.10" - - "0.12" - - "1.8" - - "2.5" - - "3.3" - - "4.9" - - "5.12" - - "6.17" - - "7.10" - - "8.16" - - "9.11" - - "10.15" - - "11.15" - - "12.2" -sudo: false -dist: trusty -env: - global: - # Suppress Node.js 0.6 compile warnings - - "CXXCOM='$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS -Wno-unused-local-typedefs -Wno-maybe-uninitialized -Wno-narrowing -Wno-strict-overflow $_CCCOMCOM $SOURCES'" -cache: - directories: - - node_modules -before_install: - - | - # Setup utility functions - function node_version_lt () { - [[ "$(v "$TRAVIS_NODE_VERSION")" -lt "$(v "${1}")" ]] - } - function npm_module_installed () { - npm -lsp ls | grep -Fq "$(pwd)/node_modules/${1}:${1}@" - } - function npm_remove_module_re () { - node -e ' - fs = require("fs"); - p = JSON.parse(fs.readFileSync("package.json", "utf8")); - r = RegExp(process.argv[1]); - for (k in p.devDependencies) { - if (r.test(k)) delete p.devDependencies[k]; - } - fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n"); - ' "$@" - } - function npm_use_module () { - node -e ' - fs = require("fs"); - p = JSON.parse(fs.readFileSync("package.json", "utf8")); - p.devDependencies[process.argv[1]] = process.argv[2]; - fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n"); - ' "$@" - } - function v () { - tr '.' '\n' <<< "${1}" \ - | awk '{ printf "%03d", $0 }' \ - | sed 's/^0*//' - } - # Configure npm - - | - # Skip updating shrinkwrap / lock - npm config set shrinkwrap false - - | - # Remove benchmark dependencies - npm_remove_module_re '(^|-)benchmark$' - # Setup Node.js version-specific dependencies - - | - # Configure eslint for linting - if node_version_lt '6.0'; then npm_remove_module_re '^eslint(-|$)' - fi - - | - # Configure istanbul for coverage - if node_version_lt '0.10'; then npm_remove_module_re '^istanbul$' - fi - - | - # Configure mocha for testing - if node_version_lt '0.8' ; then npm_use_module 'mocha' '1.21.5' - elif node_version_lt '0.10'; then npm_use_module 'mocha' '2.5.3' - elif node_version_lt '4.0' ; then npm_use_module 'mocha' '3.5.3' - elif node_version_lt '6.0' ; then npm_use_module 'mocha' '5.2.0' - fi - # Update Node.js modules - - | - # Prune & rebuild node_modules - if [[ -d node_modules ]]; then - npm prune - npm rebuild - fi -before_scrpt: - - | - # Contents of node_modules - npm -s ls ||: -script: - - | - # Run test script, depending on istanbul install - if npm_module_installed 'istanbul'; then npm run-script test-ci - else npm test - fi - - | - # Run linting, if eslint exists - if npm_module_installed 'eslint'; then npm run-script lint - fi -after_script: - - | - # Upload coverage to coveralls if exists - if [[ -e ./coverage/lcov.info ]]; then - npm install --save-dev coveralls@2 - coveralls < ./coverage/lcov.info - fi diff --git a/HISTORY.md b/HISTORY.md deleted file mode 100644 index da2bf24..0000000 --- a/HISTORY.md +++ /dev/null @@ -1,123 +0,0 @@ -0.4.0 / 2019-05-15 -================== - - * Add `SameSite=None` support - -0.3.1 / 2016-05-26 -================== - - * Fix `sameSite: true` to work with draft-7 clients - - `true` now sends `SameSite=Strict` instead of `SameSite` - -0.3.0 / 2016-05-26 -================== - - * Add `sameSite` option - - Replaces `firstPartyOnly` option, never implemented by browsers - * Improve error message when `encode` is not a function - * Improve error message when `expires` is not a `Date` - -0.2.4 / 2016-05-20 -================== - - * perf: enable strict mode - * perf: use for loop in parse - * perf: use string concatination for serialization - -0.2.3 / 2015-10-25 -================== - - * Fix cookie `Max-Age` to never be a floating point number - -0.2.2 / 2015-09-17 -================== - - * Fix regression when setting empty cookie value - - Ease the new restriction, which is just basic header-level validation - * Fix typo in invalid value errors - -0.2.1 / 2015-09-17 -================== - - * Throw on invalid values provided to `serialize` - - Ensures the resulting string is a valid HTTP header value - -0.2.0 / 2015-08-13 -================== - - * Add `firstPartyOnly` option - * Throw better error for invalid argument to parse - * perf: hoist regular expression - -0.1.5 / 2015-09-17 -================== - - * Fix regression when setting empty cookie value - - Ease the new restriction, which is just basic header-level validation - * Fix typo in invalid value errors - -0.1.4 / 2015-09-17 -================== - - * Throw better error for invalid argument to parse - * Throw on invalid values provided to `serialize` - - Ensures the resulting string is a valid HTTP header value - -0.1.3 / 2015-05-19 -================== - - * Reduce the scope of try-catch deopt - * Remove argument reassignments - -0.1.2 / 2014-04-16 -================== - - * Remove unnecessary files from npm package - -0.1.1 / 2014-02-23 -================== - - * Fix bad parse when cookie value contained a comma - * Fix support for `maxAge` of `0` - -0.1.0 / 2013-05-01 -================== - - * Add `decode` option - * Add `encode` option - -0.0.6 / 2013-04-08 -================== - - * Ignore cookie parts missing `=` - -0.0.5 / 2012-10-29 -================== - - * Return raw cookie value if value unescape errors - -0.0.4 / 2012-06-21 -================== - - * Use encode/decodeURIComponent for cookie encoding/decoding - - Improve server/client interoperability - -0.0.3 / 2012-06-06 -================== - - * Only escape special characters per the cookie RFC - -0.0.2 / 2012-06-01 -================== - - * Fix `maxAge` option to not throw error - -0.0.1 / 2012-05-28 -================== - - * Add more tests - -0.0.0 / 2012-05-28 -================== - - * Initial release diff --git a/README.md b/README.md index 857fb77..71fdac1 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,18 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] -[![Node.js Version][node-version-image]][node-version-url] -[![Build Status][travis-image]][travis-url] -[![Test Coverage][coveralls-image]][coveralls-url] +[![Node.js Version][node-image]][node-url] +[![Build Status][ci-image]][ci-url] +[![Coverage Status][coveralls-image]][coveralls-url] 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 ``` @@ -103,14 +107,39 @@ The given number will be converted to an integer by rounding down. By default, n `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. +##### partitioned + +Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-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]. +##### priority + +Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-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`. + +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. + ##### sameSite -Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-03-4.1.2.7]. +Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.7]. - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. - `false` will not set the `SameSite` attribute. @@ -119,7 +148,7 @@ Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Coo - `'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-03-4.1.2.7]. +[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. @@ -194,40 +223,75 @@ $ npm test ``` $ npm run bench -> cookie@0.3.1 bench cookie +> cookie@0.5.0 bench > node benchmark/index.js - http_parser@2.8.0 - node@6.14.2 - v8@5.1.281.111 - uv@1.16.1 - zlib@1.2.11 - ares@1.10.1-DEV - icu@58.2 - modules@48 - napi@3 - openssl@1.0.2o + 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 + cookie.parse - generic 6 tests completed. - simple x 1,200,691 ops/sec ±1.12% (189 runs sampled) - decode x 1,012,994 ops/sec ±0.97% (186 runs sampled) - unquote x 1,074,174 ops/sec ±2.43% (186 runs sampled) - duplicates x 438,424 ops/sec ±2.17% (184 runs sampled) - 10 cookies x 147,154 ops/sec ±1.01% (186 runs sampled) - 100 cookies x 14,274 ops/sec ±1.07% (187 runs sampled) + 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) ``` ## References - [RFC 6265: HTTP State Management Mechanism][rfc-6265] -- [Same-site Cookies][rfc-6265bis-03-4.1.2.7] +- [Same-site Cookies][rfc-6265bis-09-5.4.7] -[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.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 @@ -242,12 +306,12 @@ $ npm run bench [MIT](LICENSE) +[ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci +[ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master [coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master -[node-version-image]: https://badgen.net/npm/node/cookie -[node-version-url]: https://nodejs.org/en/download +[node-image]: https://badgen.net/npm/node/cookie +[node-url]: https://nodejs.org/en/download [npm-downloads-image]: https://badgen.net/npm/dm/cookie [npm-url]: https://npmjs.org/package/cookie [npm-version-image]: https://badgen.net/npm/v/cookie -[travis-image]: https://badgen.net/travis/jshttp/cookie/master -[travis-url]: https://travis-ci.org/jshttp/cookie diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..fd4a6c5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policies and Procedures + +## Reporting a Bug + +The `cookie` team and community take all security bugs seriously. Thank +you for improving the security of the project. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by emailing the current owner(s) of `cookie`. This +information can be found in the npm registry using the command +`npm owner ls cookie`. +If unsure or unable to get the information from the above, open an issue +in the [project issue tracker](https://github.com/jshttp/cookie/issues) +asking for the current contact information. + +To ensure the timely response to your report, please ensure that the entirety +of the report is contained within the email body and not solely behind a web +link or an attachment. + +At least one owner will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the owners will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. diff --git a/benchmark/parse-top.js b/benchmark/parse-top.js new file mode 100644 index 0000000..4cbfd00 --- /dev/null +++ b/benchmark/parse-top.js @@ -0,0 +1,37 @@ +/** + * 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-top.json b/benchmark/parse-top.json new file mode 100644 index 0000000..125b695 --- /dev/null +++ b/benchmark/parse-top.json @@ -0,0 +1,17 @@ +{ + "accounts.google.com": "__Ulll-UUUU=0:lllllUlUUUlUU_llUU0UUUl0lU0UUl:UUlUlUl0UU0UlUlU", + "apple.com": "lll=UU", + "cloudflare.com": "__ll_ll=llUUlU0U0UlUlUll.lllUUUUlUUUlUUlUU000UlllUl-0000000000-0-UllU00UUllllUUUllUl0l0llllUUlU0UlUUUlUUl0Ull/l0+lllllUlUlU0l0l00ll+0U0ll/l0UlU00lllllllUUll0lU00lUUUllUUlUUl", + "docs.google.com": "__Ulll-UUUU=0:lUlUlU0UUlUllUUlUllUUlUUlU0U:Ul0UllUUllll0UUl", + "drive.google.com": "__Ulll-UUUU=0:U0l0lUUllU0lllUlU0UU00UlllUUlU:lUUUllUlUUUllUUl", + "en.wikipedia.org": "UUU-Ulll-Ulllll=00-Ull-0000; UUU-Ulll-Ulllll-Ulllll=00-Ull-0000; UUU-UU=lll; UllUU=UU:UU:Ulllllllllll:00.00:-00.00:l0; UllllllUllllUllll=0.000", + "linkedin.com": "UUUUUUUUUU=llll:0000000000000000000; llll=l=0&llll=ll-ll; lllllll=\"l=0&0l0ll000-0000-00ll-0000-0l000ll00000\"; llllllll=\"l=0&00000000000000l00l0l0l-l000-00l0-00ll-l0000l000000UUUUlUlUU0llll0UlllUU0UU--UUlUlU\"; llll=\"l=UUUU00:l=U:l=U:l=U:l=U:l=0000:l=0:l=0:l=0000000000:l=0000000000:l=0:lll=UUU-UUlUlUUl0lUUlUlUllll0lllUUUU\"", + "maps.google.com": "0U_UUU=0000-00-00-00; UUU=000=lU00_U0UllU-lUlUUUllUl0l0U_lUlUUUl00UUU0llllU_UUlUUU0UllUllll0l-_lUlllUU0llll0UlUUllll_UU0U0lU-llUllll00lUllUllUlUlllU_lUUUl0ll0lUUlUlllUUl0llUUl0UU0llUlllllUllUll0UUUllUU", + "microsoft.com": "UUUUU=llllll0; lllll_UllUU=0000000000~ll=00~ll=0000l0l0l0lllll0l000000000l0l00l; lllll_UllUU=0000000000~ll=00~ll=0000l0l0l0lllll0l000000000l0l00l", + "play.google.com": "UUU=000=UllU0l0UU0llUlU0UUU0lUUUl0lUlUUllUlUl0ll0UlUlllUlUlUUlUUllUll-UUll0llll0UllUlUU0U0lUUUUU0Ull0l0l0l0lUU0UlUU000lUUUU0lU_UUlUUlUUl0UU-lUlUU0lUlUllUUUllUUllll00lllU0U0UUU0Ull", + "support.google.com": "UUU=000=l0llUUlUllU0UlllU0U0U0UlU-Ulll0lUlllU0UUllUUlUUUlllllUUUU-UUllUllU0lUU0U0U00lU0UUlUl0l0lUUlUUUUl0lUU0UUllUlUlUUlUlUUUU0ll0l0UU0lllU0lllUUUU0U0lU0U00l0Ul0UlU-U0UllU00lUUl0U; UUU=000=l0llUUlUllU0UlllU0U0U0UlU-Ulll0lUlllU0UUllUUlUUUlllllUUUU-UUllUllU0lUU0U0U00lU0UUlUl0l0lUUlUUUUl0lUU0UUllUlUlUUlUlUUUU0ll0l0UU0lllU0lllUUUU0U0lU0U00l0Ul0UlU-U0UllU00lUUl0U", + "www.google.com": "0U_UUU=0000-00-00-00; UUU=Ullll0Ullll0U0llUllU00U_lllll0lUUlUl0UllUlUUl0lUlUUUl00UUl; UUU=000=lUU0U0U0U0UllUUUlUUlUUU_UlUll_l0U0UU00lUlUlUlllllUUUl00UllllUU_0ll0UllUllUUU-UUUlllU0UlUlUllUlUllUll00UllU0U00llUUl0lU00lUlUUlllUl_U00UUlU0UU0UllUlUU0lUUlUUUl00lUUlUUUU0ll", + "youtu.be": "UUU=0; UUU=ll0UU-l0lUl; UUUUUUU_UUUU0_UUUU=0_llUUlUllU; UUUUUUU_UUUUUUU_UUUUUUUU=UlUUUlUUUlU%22", + "youtube.com": "UUU=0; UUU=l0_UlUUUlUl; UUUUUUU_UUUU0_UUUU=UUUUlUUUlll; UUUUUUU_UUUUUUU_UUUUUUUU=UlUUUlUUUlU%22", + "example.com": "" +} diff --git a/benchmark/parse.js b/benchmark/parse.js index 3ec985a..567f4b6 100644 --- a/benchmark/parse.js +++ b/benchmark/parse.js @@ -49,11 +49,11 @@ suite.add({ fn: 'var val = cookie.parse(' + JSON.stringify(gencookies(100)) + ')' }) -suite.on('start', function onCycle (event) { - process.stdout.write(' cookie.parse\n\n') +suite.on('start', function () { + process.stdout.write(' cookie.parse - generic\n\n') }) -suite.on('cycle', function onCycle (event) { +suite.on('cycle', function (event) { benchmarks.add(event.target) }) @@ -61,7 +61,7 @@ suite.on('complete', function onComplete () { benchmarks.log() }) -suite.run({async: false}) +suite.run({ async: false }) function gencookies (num) { var str = '' @@ -70,5 +70,5 @@ function gencookies (num) { str += '; foo' + i + '=bar' } - return str.substr(2) + return str.slice(2) } diff --git a/index.js b/index.js index 16f56c0..51a58cb 100644 --- a/index.js +++ b/index.js @@ -20,19 +20,69 @@ exports.serialize = serialize; * @private */ -var decode = decodeURIComponent; -var encode = encodeURIComponent; -var pairSplitRegExp = /; */; +var __toString = Object.prototype.toString /** - * RegExp to match field-content in RFC 7230 sec 3.2 + * 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. * - * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - * field-vchar = VCHAR / obs-text - * obs-text = %x80-FF + * cookie-name = token + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / + * "*" / "+" / "-" / "." / "^" / "_" / + * "`" / "|" / "~" / DIGIT / ALPHA */ -var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; +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 + * =