Skip to content

Commit

Permalink
Merge branch 'main' into fix/http2_queue
Browse files Browse the repository at this point in the history
  • Loading branch information
metcoder95 authored Oct 31, 2024
2 parents de22c58 + dac8e73 commit 9c64efa
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 3 deletions.
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,13 @@ const { kConstruct } = require('./lib/core/symbols')
// in an older version of Node, it doesn't have any use without fetch.
module.exports.caches = new CacheStorage(kConstruct)

const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/web/cookies')
const { deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require('./lib/web/cookies')

module.exports.deleteCookie = deleteCookie
module.exports.getCookies = getCookies
module.exports.getSetCookies = getSetCookies
module.exports.setCookie = setCookie
module.exports.parseCookie = parseCookie

const { parseMIMEType, serializeAMimeType } = require('./lib/web/fetch/data-url')

Expand Down
13 changes: 12 additions & 1 deletion lib/web/cookies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ function getSetCookies (headers) {
return cookies.map((pair) => parseSetCookie(pair))
}

/**
* Parses a cookie string
* @param {string} cookie
*/
function parseCookie (cookie) {
cookie = webidl.converters.DOMString(cookie)

return parseSetCookie(cookie)
}

/**
* @param {Headers} headers
* @param {Cookie} cookie
Expand Down Expand Up @@ -184,5 +194,6 @@ module.exports = {
getCookies,
deleteCookie,
getSetCookies,
setCookie
setCookie,
parseCookie
}
7 changes: 6 additions & 1 deletion lib/web/cookies/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
const { isCTLExcludingHtab } = require('./util')
const { collectASequenceOfCodePointsFast } = require('../fetch/data-url')
const assert = require('node:assert')
const { unescape } = require('node:querystring')

/**
* @description Parses the field-value attributes of a set-cookie header string.
Expand Down Expand Up @@ -76,8 +77,12 @@ function parseSetCookie (header) {

// 6. The cookie-name is the name string, and the cookie-value is the
// value string.
// https://datatracker.ietf.org/doc/html/rfc6265
// To maximize compatibility with user agents, servers that wish to
// store arbitrary data in a cookie-value SHOULD encode that data, for
// example, using Base64 [RFC4648].
return {
name, value, ...parseUnparsedAttributes(unparsedAttributes)
name, value: unescape(value), ...parseUnparsedAttributes(unparsedAttributes)
}
}

Expand Down
113 changes: 113 additions & 0 deletions test/cookie/npm-cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
'use strict'

// (The MIT License)
//
// Copyright (c) 2012-2014 Roman Shtylman <[email protected]>
// Copyright (c) 2015 Douglas Christopher Wilson <[email protected]>
//
// 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.

const { describe, it } = require('node:test')
const assert = require('node:assert')
const { parseCookie } = require('../..')

describe('parseCookie(str)', function () {
it('should parse cookie string to object', function () {
assert.deepStrictEqual(parseCookie('foo=bar'), { name: 'foo', value: 'bar' })
assert.deepStrictEqual(parseCookie('foo=123'), { name: 'foo', value: '123' })
})

it('should ignore OWS', function () {
assert.deepStrictEqual(parseCookie('FOO = bar; baz = raz'), {
name: 'FOO',
value: 'bar',
unparsed: ['baz=raz']
})
})

it('should parse cookie with empty value', function () {
assert.deepStrictEqual(parseCookie('foo=; bar='), { name: 'foo', value: '', unparsed: ['bar='] })
})

it('should parse cookie with minimum length', function () {
assert.deepStrictEqual(parseCookie('f='), { name: 'f', value: '' })
assert.deepStrictEqual(parseCookie('f=;b='), { name: 'f', value: '', unparsed: ['b='] })
})

it('should URL-decode values', function () {
assert.deepStrictEqual(parseCookie('foo="bar=123456789&name=Magic+Mouse"'), {
name: 'foo',
value: '"bar=123456789&name=Magic+Mouse"'
})

assert.deepStrictEqual(parseCookie('email=%20%22%2c%3b%2f'), { name: 'email', value: ' ",;/' })
})

it('should trim whitespace around key and value', function () {
assert.deepStrictEqual(parseCookie(' foo = "bar" '), { name: 'foo', value: '"bar"' })
assert.deepStrictEqual(parseCookie(' foo = bar ; fizz = buzz '), {
name: 'foo',
value: 'bar',
unparsed: ['fizz=buzz']
})
assert.deepStrictEqual(parseCookie(' foo = " a b c " '), { name: 'foo', value: '" a b c "' })
assert.deepStrictEqual(parseCookie(' = bar '), { name: '', value: 'bar' })
assert.deepStrictEqual(parseCookie(' foo = '), { name: 'foo', value: '' })
assert.deepStrictEqual(parseCookie(' = '), { name: '', value: '' })
assert.deepStrictEqual(parseCookie('\tfoo\t=\tbar\t'), { name: 'foo', value: 'bar' })
})

it('should return original value on escape error', function () {
assert.deepStrictEqual(parseCookie('foo=%1;bar=bar'), { name: 'foo', value: '%1', unparsed: ['bar=bar'] })
})

it('should ignore cookies without value', function () {
assert.deepStrictEqual(parseCookie('foo=bar;fizz ; buzz'), { name: 'foo', value: 'bar', unparsed: ['fizz=', 'buzz='] })
assert.deepStrictEqual(parseCookie(' fizz; foo= bar'), { name: '', value: 'fizz', unparsed: ['foo=bar'] })
})

it('should ignore duplicate cookies', function () {
assert.deepStrictEqual(parseCookie('foo=%1;bar=bar;foo=boo'), {
name: 'foo',
value: '%1',
unparsed: ['bar=bar', 'foo=boo']
})
assert.deepStrictEqual(parseCookie('foo=false;bar=bar;foo=true'), {
name: 'foo',
value: 'false',
unparsed: ['bar=bar', 'foo=true']
})
assert.deepStrictEqual(parseCookie('foo=;bar=bar;foo=boo'), {
name: 'foo',
value: '',
unparsed: ['bar=bar', 'foo=boo']
})
})

it('should parse native properties', function () {
assert.deepStrictEqual(parseCookie('toString=foo;valueOf=bar'), {
name: 'toString',
unparsed: [
'valueOf=bar'
],
value: 'foo'
})
})
})
2 changes: 2 additions & 0 deletions types/cookies.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export function getCookies (headers: Headers): Record<string, string>
export function getSetCookies (headers: Headers): Cookie[]

export function setCookie (headers: Headers, cookie: Cookie): void

export function parseCookie (cookie: string): Cookie | null

0 comments on commit 9c64efa

Please sign in to comment.