
Библиотека для парсинга куки и управления CookieJar, совместимая с RFC6265 для Node.js, с патчем безопасности CVE-2023-26136. Поддерживает создание, проверку, хранение и получение куки для HTTP-клиентов.
RFC6265 Куки и CookieJar для Node.js
var tough = require('tough-cookie'); var Cookie = tough.Cookie; var cookie = Cookie.parse(header); cookie.value = 'somethingdifferent'; header = cookie.toString();
var cookiejar = new tough.CookieJar(); cookiejar.setCookie(cookie, 'http://currentdomain.example.com/path', cb); // ... cookiejar.getCookies('http://example.com/otherpath',function(err,cookies) { res.headers['cookie'] = cookies.join('; '); });
# Установка
Это _так_ просто!
`npm install tough-cookie`
Почему такое название? Модули NPM `cookie`, `cookies` и `cookiejar` уже были заняты.
## Поддержка версий
Поддержка версий node.js будет следовать за модулем [request](https://www.npmjs.com/package/request).
# API
## tough
Функции модуля, которые вы получаете из `require('tough-cookie')`. Все могут использоваться как чистые функции и не нуждаются в «привязке».
**Примечание**: до версии 1.0.x некоторые из этих функций принимали параметр `strict`. Впоследствии он был удалён из API как больше не являющийся необходимым.
### `parseDate(string)`
Преобразует строку даты куки в `Date`. Разбор выполняется в соответствии с RFC6265, раздел 5.1.1, а не `Date.parse()`.
### `formatDate(date)`
Форматирует Date в строку RFC1123 (рекомендуемый формат RFC6265).
### `canonicalDomain(str)`
Преобразует доменное имя в каноническое доменное имя. Каноническое доменное имя — это обрезанное, приведённое к нижнему регистру, лишённое ведущей точки и, возможно, закодированное в Punycode доменное имя (раздел 5.1.2 RFC6265). По большей части эта функция идемпотентна (может быть запущена повторно на своём выводе без негативных последствий).
### `domainMatch(str,domStr[,canonicalize=true])`
Отвечает на вопрос «соответствует ли это реальное доменное имя домену в куки?». `str` — это «текущее» доменное имя, а `domStr` — «доменное имя куки». Соответствие определяется согласно RFC6265, раздел 5.1.3, но полезно думать об этом как о «совпадении суффикса».
Параметр `canonicalize` запускает два других параметра через `canonicalDomain` или нет.
### `defaultPath(path)`
Учитывая текущий путь запроса/ответа, возвращает путь, подходящий для сохранения в куки. По сути, это «каталог» «файла» в пути, но определяется разделом 5.1.4 RFC.
Параметр `path` ДОЛЖЕН быть _только_ частью пути URI (т.е. исключает имя хоста, запрос, фрагмент и т.д.). Это свойство `.pathname` вывода `uri.parse()` в node.
### `pathMatch(reqPath,cookiePath)`
Отвечает на вопрос «соответствует ли путь запроса заданному пути куки?» в соответствии с RFC6265, раздел 5.1.4. Возвращает логическое значение.
По сути, это проверка префикса, где `cookiePath` является префиксом `reqPath`.
### `parse(cookieString[, options])`
алиас для `Cookie.parse(cookieString[, options])`
### `fromJSON(string)`
алиас для `Cookie.fromJSON(string)`
### `getPublicSuffix(hostname)`
Возвращает публичный суффикс этого имени хоста. Публичный суффикс — это кратчайшее доменное имя, для которого можно установить куки. Возвращает `null`, если для имени хоста нельзя установить куки.
Например: `www.example.com` и `www.subdomain.example.com` имеют публичный суффикс `example.com`.
Дополнительную информацию см. на http://publicsuffix.org/. Этот модуль получает свой список с этого сайта. Этот вызов в настоящее время является обёрткой вокруг [метода get()](https://www.npmjs.com/package/psl#pslgetdomain) из [`psl`](https://www.npmjs.com/package/psl).
### `cookieCompare(a,b)`
Для использования с `.sort()`, сортирует список куки в рекомендуемом порядке, указанном в RFC (раздел 5.4, шаг 2). Алгоритм сортировки по порядку приоритета:
* Самый длинный `.path`
* Самое старое `.creation` (с точностью 1 мс, как у `Date`)
* Наименьший `.creationIndex` (для выхода за пределы точности 1 мс)``` javascript
var cookies = [ /* unsorted array of Cookie objects */ ];
cookies = cookies.sort(cookieCompare);
Примечание: Поскольку Date в JavaScript имеет точность до 1 мс, cookies в пределах одной миллисекунды вполне возможны. Это особенно актуально при использовании опции now в .setCookie(). Свойство .creationIndex является глобальным счетчиком процесса, присваиваемым во время создания с помощью new Cookie(). Это сохраняет дух RFC-сортировки: старые cookies идут первыми. Это отлично работает для MemoryCookieStore, поскольку заголовки Set-Cookie разбираются по порядку, но может не очень хорошо подходить для распределенных систем. Сложные Store-ы могут захотеть установить этот параметр на другие логические часы, чтобы если cookies A и B созданы в одну миллисекунду, но cookie A создана до cookie B, то A.creationIndex < B.creationIndex. Если вы хотите изменить глобальный счетчик, что вам, вероятно, не стоит делать, он хранится в Cookie.cookiesCreated.
permuteDomain(domain)Генерирует список всех возможных доменов, которым параметр соответствует domainMatch(). Может быть полезно для реализации хранилищ cookies.
permutePath(path)Генерирует список всех возможных путей, которым параметр соответствует pathMatch(). Может быть полезно для реализации хранилищ cookies.
Экспортируется через tough.Cookie.
Cookie.parse(cookieString[, options])Разбирает один HTTP-заголовок Cookie или Set-Cookie в объект Cookie. Возвращает undefined, если строку не удалось разобрать.
Параметр options не является обязательным и в настоящее время имеет только одно свойство:
true включает разбор cookies без ключа, таких как =abc и =, что не соответствует RFC.Если options не является объектом, он игнорируется, что означает, что вы можете использовать Array#map с ним.
Вот как обработать заголовок(и) Set-Cookie в ответе node HTTP/HTTPS:``` javascript if (res.headers['set-cookie'] instanceof Array) cookies = res.headers['set-cookie'].map(Cookie.parse); else cookies = [Cookie.parse(res.headers['set-cookie'])];
_Note:_ в версии 2.3.3 tough-cookie ограничивал количество пробелов перед `=` до 256 символов. Это ограничение было снято. См. [Issue 92](https://github.com/salesforce/tough-cookie/issues/92)
### Свойства
Свойства объекта Cookie:
* _key_ - строка - имя или ключ cookie (по умолчанию "")
* _value_ - строка - значение cookie (по умолчанию "")
* _expires_ - `Date` - если задано, атрибут `Expires=` cookie (по умолчанию строка `"Infinity"`). См. `setExpires()`
* _maxAge_ - секунды - если задано, атрибут `Max-Age=` _в секундах_ cookie. Также может быть установлен как строки `"Infinity"` и `"-Infinity"` для бессрочного и немедленного истечения соответственно. См. `setMaxAge()`
* _domain_ - строка - атрибут `Domain=` cookie
* _path_ - строка - `Path=` cookie
* _secure_ - логическое - флаг `Secure` cookie
* _httpOnly_ - логическое - флаг `HttpOnly` cookie
* _extensions_ - `Array` - любые нераспознанные атрибуты cookie в виде строк (даже если внутри есть знаки равенства)
* _creation_ - `Date` - когда был создан этот cookie
* _creationIndex_ - число - устанавливается при создании, используется для обеспечения более высокой точности сортировки (см. `cookieCompare(a,b)` для полного объяснения)
После того как cookie был передан через `CookieJar.setCookie()`, он будет иметь следующие дополнительные атрибуты:
* _hostOnly_ - логическое - является ли этот cookie только для хоста (т.е. поле Domain не было установлено, а подразумевалось)
* _pathIsDefault_ - логическое - если true, то на cookie не было поля Path, и для его получения использовалось `defaultPath()`.
* _creation_ - `Date` - **изменено** со времени создания на время добавления cookie в jar
* _lastAccessed_ - `Date` - время последнего доступа к cookie. Повлияет на очистку cookie после реализации. Использование `cookiejar.getCookies(...)` обновит этот атрибут.
### `Cookie([{properties}])`
Принимает объект параметров, который может содержать любые из вышеуказанных свойств Cookie, использует значения по умолчанию для неуказанных свойств.
### `.toString()`
Кодирует в значение заголовка Set-Cookie. Поле Expires устанавливается с помощью `formatDate()`, но полностью опускается, если `.expires` равно `Infinity`.
### `.cookieString()`
Кодирует в значение заголовка Cookie (т.е. свойства `.key` и `.value` объединены через '=').
### `.setExpires(String)`
Устанавливает срок действия на основе строки даты, переданной через `parseDate()`. Если parseDate возвращает `null` (т.е. не может разобрать эту строку даты), `.expires` устанавливается в `"Infinity"` (строка).
### `.setMaxAge(number)`
Устанавливает maxAge в секундах. Приводит `-Infinity` к `"-Infinity"` и `Infinity` к `"Infinity"`, чтобы он правильно сериализовался в JSON.
### `.expiryTime([now=Date.now()])`
### `.expiryDate([now=Date.now()])`
expiryTime() вычисляет абсолютное время в миллисекундах от эпохи Unix, когда этот cookie истекает. expiryDate() работает аналогично, но возвращает объект `Date`. Обратите внимание, что в обоих случаях параметр `now` должен быть в миллисекундах.
Max-Age имеет приоритет над Expires (согласно RFC). Атрибут `.creation` — или, по умолчанию, параметр `now` — используется для смещения атрибута `.maxAge`.
Если установлен Expires (`.expires`), возвращается он.
В противном случае `expiryTime()` возвращает `Infinity`, а `expiryDate()` возвращает объект `Date` для "Tue, 19 Jan 2038 03:14:07 GMT" (самая поздняя дата, которая может быть выражена 32-битным `time_t`; общий предел для большинства пользовательских агентов).
### `.TTL([now=Date.now()])`
вычисляет TTL относительно `now` (в миллисекундах). Применяются те же правила приоритета, что и для `expiryTime`/`expiryDate`.
Число `Infinity` возвращается для cookie без явного срока действия, и `0` возвращается, если cookie истек. В противном случае возвращается время жизни в миллисекундах.
### `.canonicalizedDomain()`
### `.cdomain()`
возвращает канонизированное поле `.domain`. Оно приводится к нижнему регистру и кодируется punycode (RFC3490), если домен содержит символы, не входящие в ASCII.
### `.toJSON()`
Для удобства использования `JSON.serialize(cookie)`. Возвращает простой объект `Object`, который может быть сериализован в JSON.
Любые свойства `Date` (т.е. `.expires`, `.creation` и `.lastAccessed`) экспортируются в формате ISO (`.toISOString()`).
**ПРИМЕЧАНИЕ**: Пользовательские свойства `Cookie` будут отброшены. В tough-cookie 1.x, поскольку не было явно определенного метода `.toJSON`, захватывались все перечисляемые свойства. Если вы хотите, чтобы свойство было сериализовано, добавьте имя свойства в массив `Cookie.serializableProperties`.
### `Cookie.fromJSON(strOrObj)`
Делает обратное `cookie.toJSON()`. Если передана строка, сначала выполнит `JSON.parse()`.
Любые свойства `Date` (т.е. `.expires`, `.creation` и `.lastAccessed`) разбираются через `Date.parse()`, а не через tough-cookie `parseDate`, поскольку на этом уровне обрабатываются метки времени JavaScript/JSON.
Возвращает `null` при ошибке разбора JSON.
### `.clone()`
Выполняет глубокое клонирование этого cookie, реализованное точно как `Cookie.fromJSON(cookie.toJSON())`.
### `.validate()`
Статус: *В РАЗРАБОТКЕ*. Работает для некоторых вещей, но отнюдь не всеобъемлюще.
проверяет атрибуты cookie на семантическую корректность. Полезно для проверки (lint) любых генерируемых вами заголовков Set-Cookie. Пока возвращает логическое значение, но в конечном итоге может возвращать строку с причиной — вы можете защитить свой код на будущее с помощью этой конструкции:``` javascript
if (cookie.validate() === true) {
// it's tasty
} else {
// yuck!
}
Экспортируется через tough.CookieJar.
CookieJar([store],[options])Просто используйте new CookieJar(). Если вы хотите использовать собственное хранилище, передайте его в конструктор; в противном случае будет создано и использовано MemoryCookieStore.
Объект options можно опустить; он может содержать следующие свойства:
true - отклонять cookie с доменами вроде "com" и "co.uk"false - принимать некорректные cookie, например bar и =bar, у которых подразумевается пустое имя.
Это не соответствует стандарту, но иногда используется в вебе и принимается (большинством) браузеров.Поскольку в конечном итоге этот модуль предполагает поддержку CookieJar, работающих с базами данных/удалённо/и т.д., для методов CookieJar используется стиль continuation-passing.
.setCookie(cookieOrString, currentUrl, [{options},] cb(err,cookie))Пытается установить cookie в jar. Если операция не удалась, ошибка передаётся в callback cb, в противном случае передаётся cookie. У cookie будут обновлены свойства .creation, .lastAccessed и .hostOnly.
Объект options можно опустить; он может содержать следующие свойства:
true - указывает, является ли это HTTP или non-HTTP API. Влияет на HttpOnly cookie.currentUrl начинается с https: или wss:, по умолчанию устанавливается true, иначе false.new Date() - что использовать для времени создания/доступа к cookiefalse - молча игнорировать такие вещи, как ошибки парсинга и недопустимые домены. Ошибки Store этой опцией не игнорируются.Согласно RFC, свойство .hostOnly устанавливается, если в строке cookie отсутствовал параметр "Domain=" (или .domain был равен null в объекте Cookie). В этом случае свойство .domain устанавливается в полное имя хоста currentUrl. Для сопоставления такой cookie требуется точное совпадение имени хоста (а не domainMatch, как обычно).
.setCookieSync(cookieOrString, currentUrl, [{options}])Синхронная версия setCookie; работает только с синхронными хранилищами (например, по умолчанию MemoryCookieStore).
.getCookies(currentUrl, [{options},] cb(err,cookies))Получает список cookie, которые могут быть отправлены в заголовке Cookie для текущего url.
Если возникает ошибка, она передаётся как err в callback, в противном случае передаётся Array объектов Cookie. Массив сортируется с помощью cookieCompare(), если не указана опция {sort:false}.
Объект options можно опустить; он может содержать следующие свойства:
true - указывает, является ли это HTTP или non-HTTP API. Влияет на HttpOnly cookie.currentUrl начинается с https: или wss:, по умолчанию устанавливается true, иначе false.new Date() - что использовать для времени создания/доступа к cookietrue - выполнять проверку cookie на истечение срока и асинхронно удалять просроченные cookie из хранилища. Использование false вернёт просроченные cookie и не удалит их из хранилища (что может быть полезно для потенциального воспроизведения заголовков Set-Cookie).false - если true, не ограничивать cookie по пути. По умолчанию используется соответствующее RFC ограничение по пути. : может не поддерживаться нижележащим хранилищем (по умолчанию поддерживает).Свойство .lastAccessed возвращаемых cookie будет обновлено.
.getCookiesSync(currentUrl, [{options}])Синхронная версия getCookies; работает только с синхронными хранилищами (например, по умолчанию MemoryCookieStore).
.getCookieString(...)Принимает те же опции, что и .getCookies(), но передаёт в callback строку, подходящую для заголовка Cookie, а не массив. Просто отображает массив Cookie через .cookieString().
.getCookieStringSync(...)Синхронная версия getCookieString; работает только с синхронными хранилищами (например, по умолчанию MemoryCookieStore).
.getSetCookieStrings(...)Возвращает массив строк, подходящих для заголовков Set-Cookie. Принимает те же опции, что и .getCookies(). Просто отображает массив cookie через .toString().
.getSetCookieStringsSync(...)Синхронная версия getSetCookieStrings; работает только с синхронными хранилищами (например, по умолчанию MemoryCookieStore).
.serialize(cb(err,serializedObject))Сериализует Jar, если нижележащее хранилище поддерживает .getAllCookies.
ПРИМЕЧАНИЕ: Пользовательские свойства Cookie будут отброшены. Если вы хотите, чтобы свойство было сериализовано, добавьте имя свойства в массив Cookie.serializableProperties.
См. [Serialization Format].
.serializeSync()Синхронная версия .serialize
.toJSON()Псевдоним .serializeSync() для удобства JSON.stringify(cookiejar).
CookieJar.deserialize(serialized, [store], cb(err,object))Создаётся новый Jar, и сериализованные cookie добавляются в нижележащее хранилище. Каждый Cookie добавляется через store.putCookie в порядке их появления в сериализации.
Аргумент store необязателен, но должен быть экземпляром Store. По умолчанию создаётся новый экземпляр MemoryCookieStore.
Для удобства, если serialized является строкой, она сначала пропускается через JSON.parse. Если это вызывает ошибку, она передаётся в callback.
CookieJar.deserializeSync(serialized, [store])Синхронная версия .deserialize. Примечание: для работы store должно быть синхронным.
CookieJar.fromJSON(string)Псевдоним .deserializeSync для согласованности с Cookie.fromJSON().
.clone([store,]cb(err,newJar))Создаёт глубокую копию этого jar. Изменения оригинала не повлияют на копию, и наоборот.
Аргумент store необязателен, но должен быть экземпляром Store. По умолчанию создаётся новый экземпляр MemoryCookieStore. Перенос между типами хранилищ поддерживается, если источник реализует .getAllCookies(), а назначение — .putCookie().
.cloneSync([store])Синхронная версия .clone, возвращающая новый экземпляр CookieJar.
Аргумент store необязателен, но если указан, должен быть синхронным экземпляром Store. Если не передан, используется новый экземпляр MemoryCookieStore.
Источник и назначение должны быть синхронными Store. Если одно или оба хранилища асинхронны, используйте .clone. Напоминаем, что MemoryCookieStore поддерживает как синхронные, так и асинхронные вызовы API.
.removeAllCookies(cb(err))Удаляет все cookie из jar.
Это новая обратно совместимая возможность tough-cookie версии 2.5, поэтому не все Store реализуют её эффективно. Для Store, которые не реализуют removeAllCookies, используется запасной вариант: вызов removeCookie после getAllCookies. Если getAllCookies не удаётся или не реализован в Store, возвращается эта ошибка. Если один или несколько вызовов removeCookie не удались, возвращается только первая ошибка.
.removeAllCookiesSync()Синхронная версия .removeAllCookies()
Базовый класс для хранилищ CookieJar. Доступен как tough.Store.
Модель хранения для каждого экземпляра CookieJar может быть заменена собственной реализацией. По умолчанию используется MemoryCookieStore, который находится в файле lib/memstore.js. API использует стиль continuation-passing для поддержки асинхронных хранилищ.
Store должны наследовать от базового класса Store, доступного как require('tough-cookie').Store.
Store по умолчанию асинхронны, но если store.synchronous установлено в true, то можно использовать методы *Sync содержащего CookieJar (однако стиль continuation-passing
Все параметры domain будут нормализованы перед вызовом.
Хранилище Cookie должно реализовывать все следующие методы.
store.findCookie(domain, path, key, cb(err,cookie))Извлекает cookie с заданными domain, path и key (т.е. именем). RFC требует, чтобы в хранилище существовала ровно одна такая cookie. Если хранилище использует версионирование, это означает, что должна быть возвращена последняя/самая новая такая cookie.
Callback принимает ошибку и результирующий объект Cookie. Если cookie не найдена, вместо неё ДОЛЖЕН быть передан null (т.е. не ошибка).
store.findCookies(domain, path, cb(err,cookies))Находит cookie, соответствующие заданным domain и path. Чаще всего вызывается в контексте cookiejar.getCookies() выше.
Если cookie не найдены, callback ДОЛЖЕН получить пустой массив.
Полученный список будет проверен на применимость к текущему запросу согласно RFC (domain-match, path-match, http-only-flag, secure-flag, expiry и т.д.), поэтому при реализации этого метода можно использовать оптимистичный алгоритм поиска. Однако используемый алгоритм поиска ДОЛЖЕН пытаться найти cookie, которые domainMatch() домен и pathMatch() путь, чтобы ограничить объём необходимой проверки.
Начиная с версии 0.9.12, опция allPaths в cookiejar.getCookies() выше приведёт к тому, что путь здесь будет null. Если путь null, сопоставление по пути НЕ ДОЛЖНО выполняться (только по домену).
store.putCookie(cookie, cb(err))Добавляет новую cookie в хранилище. Реализация ДОЛЖНА заменить любую существующую cookie с теми же свойствами .domain, .path и .key — в зависимости от природы реализации, возможно, что между вызовом fetchCookie и putCookie может произойти дублирующий putCookie.
Объект cookie НЕ ДОЛЖЕН изменяться; вызывающий код уже обновил свойства .creation и .lastAccessed.
Передайте ошибку, если cookie не может быть сохранена.
store.updateCookie(oldCookie, newCookie, cb(err))Обновляет существующую cookie. Реализация ДОЛЖНА обновить .value для cookie с теми же domain, .path и .key. Реализация ДОЛЖНА проверить, что старое значение в хранилище эквивалентно oldCookie — способ разрешения конфликта остаётся на усмотрение хранилища.
Свойство .lastAccessed всегда будет различаться между двумя объектами (с точностью, возможной для часов JavaScript). И .creation, и .creationIndex гарантированно одинаковы. Store могут игнорировать или откладывать изменение .lastAccessed ценой влияния на то, как cookie выбираются для автоматического удаления (например, наименее недавно использованные, что реализуется хранилищем).
Store могут захотеть оптимизировать изменение .value cookie в хранилище вместо сохранения новой cookie. Если реализация не определяет этот метод, к объекту хранилища будет добавлена заглушка, вызывающая putCookie(newCookie,cb).
Объекты newCookie и oldCookie НЕ ДОЛЖНЫ изменяться.
Передайте ошибку, если newCookie не может быть сохранена.
store.removeCookie(domain, path, key, cb(err))Удаляет cookie из хранилища (см. примечания к findCookie об ограничении уникальности).
Реализация НЕ ДОЛЖНА передавать ошибку, если cookie не существует; ошибка передаётся только при неудаче удаления существующей cookie.
store.removeCookies(domain, path, cb(err))Удаляет соответствующие cookie из хранилища. Параметр path необязателен; если он отсутствует, это означает, что должны быть удалены все пути в домене.
Передайте ошибку ТОЛЬКО в случае, если удаление какой-либо существующей cookie не удалось.
store.removeAllCookies(cb(err))Необязательно. Удаляет все cookie из хранилища.
Передайте ошибку, если одна или несколько cookie не могут быть удалены.
Примечание: Новый метод, начиная с tough-cookie версии 2.5, поэтому не все Store будут его реализовывать, и некоторые Store могут принять решение не реализовывать его.
store.getAllCookies(cb(err, cookies))Необязательно. Возвращает Array всех cookie во время jar.serialize(). Элементами массива могут быть настоящие объекты Cookie или общие Object со структурой данных [Serialization Format].
Cookie ДОЛЖНЫ быть возвращены в порядке создания, чтобы сохранить сортировку через compareCookies(). Для справки: MemoryCookieStore сортирует по .creationIndex, поскольку внутри использует настоящие объекты Cookie. Если вы не возвращаете cookie в порядке создания, они всё равно будут отсортированы по времени создания, но это имеет точность только 1 мс. См. compareCookies для подробностей.
Передайте ошибку, если извлечение не удалось.
Примечание: не все Store могут реализовать это из-за технических ограничений, поэтому это необязательно.
Наследуется от Store.
Реализация синхронного хранилища CookieJar только в памяти, используемая по умолчанию. Несмотря на синхронную реализацию, она пригодна для использования как с синхронными, так и с асинхронными формами API CookieJar. Поддерживает сериализацию, getAllCookies и removeAllCookies.
Ниже приведены некоторые реализации Store, созданные и поддерживаемые сообществом. Они не являются официальными, и мы не ручаемся за них, но возможно, вам будет интересно взглянуть:
db-cookie-store: SQL, включая базы данных на основе SQLitefile-cookie-store: Формат файлов cookie Netscape на дискеredis-cookie-store: Redistough-cookie-filestore: JSON на дискеtough-cookie-web-storage-store: DOM localStorage и sessionStorageПРИМЕЧАНИЕ: если вы хотите, чтобы пользовательские свойства Cookie были сериализованы, добавьте имя свойства в Cookie.serializableProperties.```js
{
// The version of tough-cookie that serialized this jar.
version: '[email protected]',
// add the store type, to make humans happy:
storeType: 'MemoryCookieStore',
// CookieJar configuration:
rejectPublicSuffixes: true,
// ... future items go here
// Gets filled from jar.store.getAllCookies():
cookies: [
{
key: 'string',
value: 'string',
// ...
/* other Cookie.serializableProperties go here */
}
]
}
# Авторское право и Лицензия
BSD-3-Clause:```text
Copyright (c) 2015, Salesforce.com, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of Salesforce.com nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
MemoryCookieStore