Skip to content

Commit

Permalink
Document cookieCompare
Browse files Browse the repository at this point in the history
  • Loading branch information
colincasey committed Apr 12, 2024
1 parent 17c8081 commit 7a5234f
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 9 deletions.
1 change: 1 addition & 0 deletions api/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ docs/*.md

# subsequent PRs will un-ignore areas that are under review until
# all docs are complete and we can drop this ignore file entirely
!docs/tough-cookie.cookiecompare.md
65 changes: 65 additions & 0 deletions api/docs/tough-cookie.cookiecompare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [tough-cookie](./tough-cookie.md) &gt; [cookieCompare](./tough-cookie.cookiecompare.md)

## cookieCompare() function

A comparison function that can be used with [Array.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)<!-- -->, which orders a list of cookies into the recommended order given in Step 2 of [RFC6265 - Section 5.4](https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4)<!-- -->.

The sort algorithm is, in order of precedence:

- Longest [Cookie.path](./tough-cookie.cookie.path.md)

- Oldest [Cookie.creation](./tough-cookie.cookie.creation.md) (which has a 1-ms precision, same as Date)

- Lowest [Cookie.creationIndex](./tough-cookie.cookie.creationindex.md) (to get beyond the 1-ms precision)

**Signature:**

```typescript
export declare function cookieCompare(a: Cookie, b: Cookie): number;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| a | [Cookie](./tough-cookie.cookie.md) | the first Cookie for comparison |
| b | [Cookie](./tough-cookie.cookie.md) | the second Cookie for comparison |

**Returns:**

number

## Remarks

\#\#\# RFC6265 - Section 5.4 - Step 2

The user agent SHOULD sort the cookie-list in the following order:

- Cookies with longer paths are listed before cookies with shorter paths.

- Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times.

NOTE: Not all user agents sort the cookie-list in this order, but this order reflects common practice when this document was written, and, historically, there have been servers that (erroneously) depended on this order.

\#\#\# Custom Store Implementors

Since the JavaScript Date is limited to a 1-ms precision, cookies within the same millisecond are entirely possible. This is especially true when using the `now` option to . The [Cookie.creationIndex](./tough-cookie.cookie.creationindex.md) property is a per-process global counter, assigned during construction with `new Cookie()`<!-- -->, which preserves the spirit of the RFC sorting: older cookies go first. This works great for [MemoryCookieStore](./tough-cookie.memorycookiestore.md) since `Set-Cookie` headers are parsed in order, but is not so great for distributed systems.

Sophisticated Stores may wish to set this to some other logical clock so that if cookies `A` and `B` are created in the same millisecond, but cookie `A` is created before cookie `B`<!-- -->, then `A.creationIndex < B.creationIndex`<!-- -->.

## Example


```
const cookies = [
new Cookie({ key: 'a', value: '' }),
new Cookie({ key: 'b', value: '' }),
new Cookie({ key: 'c', value: '', path: '/path' }),
new Cookie({ key: 'd', value: '', path: '/path' }),
]
cookies.sort(cookieCompare)
// cookie sort order would be ['c', 'd', 'a', 'b']
```

65 changes: 56 additions & 9 deletions lib/cookie/cookieCompare.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,69 @@
import { safeToString } from '../utils'
import * as validators from '../validators'
import type { Cookie } from './cookie'
/* Section 5.4 part 2:
* "* Cookies with longer paths are listed before cookies with
* shorter paths.
*
* * Among cookies that have equal-length path fields, cookies with
* earlier creation-times are listed before cookies with later
* creation-times."
*/

/**
* The maximum timestamp a cookie, in milliseconds. The value is (2^31 - 1) seconds since the Unix
* epoch, corresponding to 2038-01-19.
*/
const MAX_TIME = 2147483647000

/** Compares two cookies for sorting. */
/**
* A comparison function that can be used with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort | Array.sort()},
* which orders a list of cookies into the recommended order given in Step 2 of {@link https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 | RFC6265 - Section 5.4}.
*
* The sort algorithm is, in order of precedence:
*
* - Longest {@link Cookie.path}
*
* - Oldest {@link Cookie.creation} (which has a 1-ms precision, same as Date)
*
* - Lowest {@link Cookie.creationIndex} (to get beyond the 1-ms precision)
*
* @remarks
* ### RFC6265 - Section 5.4 - Step 2
*
* The user agent SHOULD sort the cookie-list in the following order:
*
* - Cookies with longer paths are listed before cookies with shorter paths.
*
* - Among cookies that have equal-length path fields, cookies with
* earlier creation-times are listed before cookies with later
* creation-times.
*
* NOTE: Not all user agents sort the cookie-list in this order, but
* this order reflects common practice when this document was
* written, and, historically, there have been servers that
* (erroneously) depended on this order.
*
* ### Custom Store Implementors
*
* Since the JavaScript Date is limited to a 1-ms precision, cookies within the same millisecond are entirely possible.
* This is especially true when using the `now` option to {@link Cookie.setCookie()}. The {@link Cookie.creationIndex}
* property is a per-process global counter, assigned during construction with `new Cookie()`, which preserves the spirit
* of the RFC sorting: older cookies go first. This works great for {@link MemoryCookieStore} since `Set-Cookie` headers
* are parsed in order, but is not so great for distributed systems.
*
* Sophisticated Stores may wish to set this to some other
* logical clock so that if cookies `A` and `B` are created in the same millisecond, but cookie `A` is created before
* cookie `B`, then `A.creationIndex < B.creationIndex`.
*
* @example
* ```
* const cookies = [
* new Cookie({ key: 'a', value: '' }),
* new Cookie({ key: 'b', value: '' }),
* new Cookie({ key: 'c', value: '', path: '/path' }),
* new Cookie({ key: 'd', value: '', path: '/path' }),
* ]
* cookies.sort(cookieCompare)
* // cookie sort order would be ['c', 'd', 'a', 'b']
* ```
*
* @param a - the first Cookie for comparison
* @param b - the second Cookie for comparison
* @public
*/
export function cookieCompare(a: Cookie, b: Cookie): number {
validators.validate(validators.isObject(a), safeToString(a))
validators.validate(validators.isObject(b), safeToString(b))
Expand Down

0 comments on commit 7a5234f

Please sign in to comment.