RFC 9111 · июнь 2022
Кэширование HTTP
Редакторы: R. Fielding, Adobe; M. Nottingham, Fastly; J. Reschke, greenbytes. STD 98. Категория: процесс стандартизации. ISSN 2070-1721. Июнь 2022. Заменяет RFC 7234.
Аннотация
Протокол передачи гипертекста HTTP — прикладной протокол без сохранения состояния для распределённых совместных гипертекстовых информационных систем. Документ определяет HTTP-кэши и связанные поля заголовков, управляющие поведением кэша или указывающие на сообщения ответа, пригодные для кэширования.
Документ заменяет RFC 7234.
Статус документа
Это документ процесса стандартизации Интернета.
Документ подготовлен Инженерной группой Интернета (IETF). Он отражает консенсус сообщества IETF, прошёл публичное обсуждение и одобрен к публикации Руководящей группой инженерных работ Интернета (IESG). Дополнительные сведения о стандартах Интернета приведены в разделе 2 RFC 7841.
Информация о текущем статусе документа, исправлениях и порядке отправки отзывов доступна по адресу https://www.rfc-editor.org/info/rfc9111.
Уведомление об авторских правах
Copyright (c) 2022 IETF Trust и лица, указанные в качестве авторов документа. Все права защищены.
На документ распространяются BCP 78 и Правовые положения IETF Trust, относящиеся к документам IETF (https://trustee.ietf.org/license-info), действовавшие на дату публикации. Внимательно ознакомьтесь с ними: они описывают ваши права и ограничения в отношении документа. Компоненты кода, извлечённые из документа, должны включать текст пересмотренной лицензии BSD, как описано в разделе 4.e Правовых положений Trust, и предоставляются без гарантий согласно этой лицензии.
Документ может содержать материалы из документов или вкладов IETF, опубликованных либо предоставленных для публичного доступа до 10 ноября 2008 года. Лица, обладающие авторскими правами на некоторые из этих материалов, могли не предоставить IETF Trust право разрешать изменения таких материалов вне процесса стандартизации IETF. Без получения надлежащей лицензии от обладателей авторских прав на такие материалы документ нельзя изменять вне процесса стандартизации IETF или создавать на его основе производные произведения вне этого процесса, кроме форматирования для публикации в качестве RFC или перевода на другие языки.
1. Введение
Протокол передачи гипертекста HTTP — прикладной протокол запросов и ответов без сохранения состояния. Он использует расширяемую семантику и самоописательные сообщения для гибкого взаимодействия с сетевыми гипертекстовыми информационными системами. Обычно он применяется в распределённых информационных системах, где кэширование ответов может повысить производительность. Документ определяет аспекты HTTP, связанные с кэшированием и повторным использованием сообщений ответа.
HTTP-кэш — локальное хранилище сообщений ответа и подсистема, управляющая их сохранением, извлечением и удалением. Кэш сохраняет пригодные для кэширования ответы, чтобы уменьшить время ответа и расход сетевой полосы при последующих эквивалентных запросах. Любой клиент или сервер МОЖЕТ (MAY) использовать кэш, кроме случаев работы в качестве туннеля (раздел 3.7 [HTTP]).
Общий кэш хранит ответы для повторного использования более чем одним пользователем; такие кэши обычно, но не всегда, развёртываются как часть посредника. Частный кэш, напротив, предназначен одному пользователю и часто развёртывается как компонент пользовательского агента.
Цель кэширования HTTP — значительно повысить производительность, повторно используя предыдущее сообщение ответа для текущего запроса. Кэш считает сохранённый ответ «актуальным» согласно разделу 4.2, если его можно повторно использовать без «проверки» — обращения к исходному серверу для выяснения, остаётся ли кэшированный ответ действительным для этого запроса. Поэтому при каждом повторном использовании актуального ответа можно уменьшить и задержку, и сетевые накладные расходы. Если кэшированный ответ не актуален, его всё ещё можно повторно использовать, если проверка способна обновить его актуальность (раздел 4.3) или исходный сервер недоступен (раздел 4.2.4).
Документ заменяет RFC 7234; изменения кратко изложены в приложении B.
1.1. Обозначения требований
Ключевые слова MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY и OPTIONAL следует толковать согласно BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они написаны целиком прописными буквами, как показано здесь.
Раздел 2 [HTTP] определяет критерии соответствия и рассматривает обработку ошибок.
1.2. Обозначение синтаксиса
Спецификация использует расширенную форму Бэкуса — Наура ABNF из [RFC5234], дополненную обозначением чувствительности строк к регистру, определённым в [RFC7405].
Также применяется расширение для списков из раздела 5.6.1 [HTTP], позволяющее компактно определять списки, разделённые запятыми, с помощью оператора # — аналогично тому, как оператор * обозначает повторение. В приложении A приведена собранная грамматика с раскрытием всех операторов списков в стандартную запись ABNF.
1.2.1. Заимствованные правила
Посредством ссылки включено основное правило DIGIT — десятичная цифра 0–9 — из приложения B.1 [RFC5234].
[HTTP] определяет следующие правила:
HTTP-date = <HTTP-date, см. [HTTP], раздел 5.6.7> OWS = <OWS, см. [HTTP], раздел 5.6.3> field-name = <field-name, см. [HTTP], раздел 5.1> quoted-string = <quoted-string, см. [HTTP], раздел 5.6.4> token = <token, см. [HTTP], раздел 5.6.2>
1.2.2. Разница в секундах
Правило delta-seconds задаёт неотрицательное целое число, представляющее время в секундах.
delta-seconds = 1*DIGIT
Получателю, разбирающему значение delta-seconds и преобразующему его в двоичную форму, следует использовать арифметический тип с диапазоном неотрицательных целых чисел не менее 31 бита. Если кэш получает значение delta-seconds больше максимального представимого им целого числа или возникает переполнение при последующих вычислениях, кэш ОБЯЗАН (MUST) считать значение равным 2147483648 (2^31) либо наибольшему положительному целому числу, которое он может удобно представить.
Примечание: значение 2147483648 приведено по историческим причинам и обозначает бесконечность — более 68 лет. Его не обязательно хранить в двоичном виде: при переполнении реализация может сформировать его как строку, даже если вычисления выполняются арифметическим типом, не способным непосредственно представить это число. Важно обнаружить переполнение и не рассматривать его как отрицательное значение в последующих вычислениях.
2. Обзор работы кэша
Правильная работа кэша сохраняет семантику HTTP-передач, сокращая передачу информации, уже находящейся в кэше. Общая терминология и основные понятия HTTP приведены в разделе 3 [HTTP].
Хотя кэширование в HTTP полностью НЕОБЯЗАТЕЛЬНО (OPTIONAL), можно предположить, что повторное использование кэшированного ответа желательно и является поведением по умолчанию, если ему не препятствуют требования или локальная конфигурация. Поэтому требования к HTTP-кэшам сосредоточены на предотвращении сохранения непригодного для повторного использования ответа и ненадлежащего повторного использования сохранённого ответа, а не на требовании всегда сохранять и повторно использовать определённые ответы.
«Ключ кэша» — информация, которую кэш использует для выбора ответа. Как минимум он состоит из метода запроса и целевого URI, использованных для получения сохранённого ответа; метод определяет, при каких обстоятельствах ответ можно использовать для последующего запроса. Однако многие распространённые HTTP-кэши сегодня сохраняют только ответы на GET и потому используют в качестве ключа лишь URI.
Кэш может сохранять несколько ответов для цели запроса, в отношении которой выполняется согласование содержимого. Такие ответы различаются добавлением некоторых полей заголовка исходного запроса в ключ кэша с использованием информации поля заголовка ответа Vary согласно разделу 4.1.
Кэши могут включать в ключ дополнительные сведения. Например, кэши пользовательских агентов могут включать идентичность ссылающегося сайта, создавая «двойной ключ» кэша для предотвращения некоторых рисков конфиденциальности (раздел 7.2).
Чаще всего кэши хранят успешный результат запроса на получение: ответ 200 (OK) на GET, содержащий представление целевого ресурса (раздел 9.3.1 [HTTP]). Однако можно сохранять также перенаправления, отрицательные результаты, например 404 (Not Found), неполные результаты, например 206 (Partial Content), и ответы на методы, отличные от GET, если определение метода допускает такое кэширование и определяет подходящий ключ кэша.
Кэш считается «отключённым», если не может связаться с исходным сервером или иным образом найти путь пересылки запроса. При некоторых обстоятельствах отключённый кэш может выдавать устаревшие ответы (раздел 4.2.4).
3. Сохранение ответов в кэшах
Кэш НЕ ДОЛЖЕН (MUST NOT) сохранять ответ на запрос, если не выполнены все следующие условия:
— метод запроса понятен кэшу; — код состояния ответа является окончательным (раздел 15 [HTTP]); — если код состояния 206 или 304 либо присутствует директива кэша must-understand (раздел 5.2.2.3), кэш понимает код состояния ответа; — в ответе отсутствует директива кэша no-store (раздел 5.2.2.5); — для общего кэша: директива ответа private отсутствует либо разрешает общему кэшу сохранить изменённый ответ (раздел 5.2.2.7); — для общего кэша: в запросе отсутствует поле заголовка Authorization (раздел 11.6.2 [HTTP]) либо в ответе присутствует директива, явно разрешающая общее кэширование (раздел 3.5); — ответ содержит хотя бы одно из следующего: директиву ответа public (раздел 5.2.2.9); директиву ответа private, если кэш не общий (раздел 5.2.2.7); поле заголовка Expires (раздел 5.3); директиву ответа max-age (раздел 5.2.2.1); для общего кэша — директиву ответа s-maxage (раздел 5.2.2.10); расширение кэша, разрешающее кэширование (раздел 5.2.3); либо код состояния, определённый как допускающий эвристическое кэширование (раздел 4.2.2).
Расширение кэша может переопределить любое из перечисленных требований; см. раздел 5.2.3.
В этом контексте кэш «понял» метод запроса или код состояния ответа, если он распознаёт его и реализует всё предусмотренное поведение, связанное с кэшированием.
При обычной работе некоторые кэши не сохраняют ответ, не имеющий ни валидатора кэша, ни явного времени истечения, поскольку такие ответы обычно бесполезно хранить. Однако сохранять их кэшам не запрещено.
3.1. Сохранение полей заголовков и трейлеров
При сохранении ответа кэши ОБЯЗАНЫ (MUST) включать все полученные поля заголовка ответа, в том числе нераспознанные; это обеспечивает успешное внедрение новых полей HTTP-заголовков. Однако предусмотрены исключения:
— согласно разделу 7.6.1 [HTTP], поле заголовка Connection и поля, им перечисленные, требуется удалить перед пересылкой сообщения. Это МОЖНО (MAY) реализовать удалением перед сохранением; — аналогично семантика некоторых полей требует удалить их перед пересылкой сообщения; это МОЖНО (MAY) реализовать удалением перед сохранением. Примеры приведены в разделе 7.6.1 [HTTP]; — директивы кэша no-cache (раздел 5.2.2.4) и private (раздел 5.2.2.7) могут иметь аргументы, запрещающие сохранение полей заголовка соответственно всеми кэшами и общими кэшами; — поля заголовков, специфичные для прокси, используемого кэшем при пересылке запроса, НЕ ДОЛЖНЫ (MUST NOT) сохраняться, если только кэш не включает идентичность прокси в ключ кэша. Фактически это ограничивается Proxy-Authenticate (раздел 11.7.1 [HTTP]), Proxy-Authentication-Info (раздел 11.7.3 [HTTP]) и Proxy-Authorization (раздел 11.7.2 [HTTP]).
Кэши МОГУТ (MAY) сохранять поля трейлера отдельно от полей заголовка либо отбрасывать их. Кэши НЕ ДОЛЖНЫ (MUST NOT) объединять поля трейлера с полями заголовка.
3.2. Обновление сохранённых полей заголовка
В некоторых ситуациях кэши обязаны обновлять поля заголовка сохранённого ответа полями другого, обычно более нового ответа; см., например, разделы 3.4, 4.3.4 и 4.3.5.
При этом кэш ОБЯЗАН (MUST) добавить в сохранённый ответ каждое поле заголовка предоставленного ответа, заменив уже присутствующие значения полей, за следующими исключениями:
— поля заголовков, исключённые из сохранения разделом 3.1; — поля, от которых зависит сохранённый ответ кэша, как описано ниже; — поля, которые получатель автоматически обрабатывает и удаляет, как описано ниже; — поле заголовка Content-Length.
Иногда кэши, особенно в пользовательских агентах, сохраняют результат обработки полученного ответа, а не сам ответ. Обновление полей заголовка, влияющих на эту обработку, может привести к несогласованному поведению и проблемам безопасности. В такой ситуации кэши МОГУТ (MAY) в исключительном порядке пропускать эти поля при обновлении сохранённых ответов, но им СЛЕДУЕТ (SHOULD) ограничивать исключения полями, необходимыми для обеспечения целостности сохранённого ответа.
Например, браузер может декодировать кодирование содержимого ответа в процессе получения, из-за чего сохранённые данные перестанут соответствовать исходным метаданным ответа. Обновление этих метаданных другим полем Content-Encoding было бы проблематичным. Аналогично браузер может сохранить дерево HTML после разбора вместо содержимого, полученного в ответе; обновление Content-Type в этом случае не сработает, поскольку любые предположения о формате, сделанные при разборе, теперь будут недействительны.
Кроме того, некоторые поля автоматически обрабатываются и удаляются реализацией HTTP, например Content-Range. Реализации МОГУТ (MAY) автоматически исключать такие поля из обновлений, даже если обработка фактически не происходила.
Префикс Content-* не является признаком исключения поля заголовка из обновления: это соглашение для заголовков MIME, а не HTTP.
3.3. Сохранение неполных ответов
Если метод запроса — GET, код состояния ответа — 200 (OK) и весь раздел заголовков ответа получен, кэш МОЖЕТ (MAY) сохранить неполный ответ (раздел 6.1 [HTTP]) при условии, что он помечен как неполный. Аналогично ответ 206 (Partial Content) МОЖНО (MAY) сохранить как неполный ответ 200 (OK). Однако кэш НЕ ДОЛЖЕН (MUST NOT) сохранять неполные ответы или ответы с частичным содержимым, если он не поддерживает поля заголовков Range и Content-Range либо не понимает используемые в них единицы диапазона.
Кэш МОЖЕТ (MAY) завершить сохранённый неполный ответ последующим запросом диапазона (раздел 14.2 [HTTP]) и объединением успешного ответа с сохранённым согласно разделу 3.4. Кэш НЕ ДОЛЖЕН (MUST NOT) использовать неполный ответ для ответа на запрос, пока он не завершён, если только запрос не является частичным и не указывает диапазон, полностью содержащийся в неполном ответе. Кэш НЕ ДОЛЖЕН (MUST NOT) отправлять клиенту частичный ответ без явной маркировки кодом 206 (Partial Content).
3.4. Объединение частичного содержимого
Ответ может передать лишь часть представления, если соединение закрылось преждевременно или запрос использовал одно либо несколько указаний Range (раздел 14.2 [HTTP]). После нескольких таких передач кэш может получить несколько диапазонов одного представления. Кэш МОЖЕТ (MAY) объединить их в один сохранённый ответ и повторно использовать его для последующих запросов, если у всех диапазонов один и тот же строгий валидатор и кэш соблюдает клиентские требования раздела 15.3.7.3 [HTTP].
При объединении нового ответа с одним или несколькими сохранёнными кэш ОБЯЗАН (MUST) обновить поля заголовка сохранённого ответа полями нового согласно разделу 3.2.
3.5. Сохранение ответов на аутентифицированные запросы
Общий кэш НЕ ДОЛЖЕН (MUST NOT) использовать кэшированный ответ на запрос с полем Authorization (раздел 11.6.2 [HTTP]) для какого-либо последующего запроса, если только ответ не содержит поле Cache-Control с директивой ответа (раздел 5.2.2), разрешающей его сохранение общим кэшем, а кэш не соблюдает требования этой директивы для данного ответа.
В спецификации такой эффект имеют директивы ответа must-revalidate (раздел 5.2.2.2), public (раздел 5.2.2.9) и s-maxage (раздел 5.2.2.10).
4. Формирование ответов из кэша
Получив запрос, кэш НЕ ДОЛЖЕН (MUST NOT) повторно использовать сохранённый ответ, если не выполнены все условия:
— целевой URI полученного запроса (раздел 7.1 [HTTP]) совпадает с URI сохранённого ответа; — метод запроса, связанный с сохранённым ответом, допускает его использование для полученного запроса; — поля заголовка запроса, указанные сохранённым ответом, если они есть, совпадают с полями полученного запроса (раздел 4.1); — сохранённый ответ не содержит директивы no-cache (раздел 5.2.2.4), если только он успешно не проверен (раздел 4.3); — сохранённый ответ актуален (раздел 4.2), либо разрешён к выдаче в устаревшем виде (раздел 4.2.4), либо успешно проверен (раздел 4.3).
Расширение кэша может переопределить любое из перечисленных требований; см. раздел 5.2.3.
Когда сохранённый ответ используется для запроса без проверки, кэш ОБЯЗАН (MUST) сформировать поле заголовка Age (раздел 5.1), заменив любое имеющееся поле значением текущего возраста current_age сохранённого ответа; см. раздел 4.2.3.
Кэш ОБЯЗАН (MUST) пропускать запросы с небезопасными методами (раздел 9.2.1 [HTTP]) на исходный сервер: кэш не вправе формировать ответ на такой запрос до его пересылки и получения соответствующего ответа.
Небезопасные запросы также могут делать уже сохранённые ответы недействительными; см. раздел 4.4.
Кэш может использовать сохранённый или пригодный к сохранению ответ для нескольких запросов, если ему разрешено повторно использовать этот ответ для соответствующих запросов. Это позволяет «сворачивать запросы»: при промахе кэша объединять несколько входящих запросов в один пересылаемый, уменьшая нагрузку на исходный сервер и сеть. Однако если кэш не может использовать полученный ответ для некоторых или всех объединённых запросов, ему придётся переслать соответствующие запросы, что может добавить задержку.
Если сохранено несколько подходящих ответов, кэш ОБЯЗАН (MUST) использовать самый свежий по полю заголовка Date. Он также может переслать запрос с Cache-Control: max-age=0 или Cache-Control: no-cache, чтобы определить, какой ответ использовать.
Кэш без часов (раздел 5.6.7 [HTTP]) ОБЯЗАН (MUST) повторно проверять сохранённые ответы при каждом использовании.
4.1. Вычисление ключей кэша с полем заголовка Vary
Когда кэш получает запрос, который может быть удовлетворён сохранённым ответом с полем заголовка Vary (раздел 12.5.5 [HTTP]), он НЕ ДОЛЖЕН (MUST NOT) использовать этот ответ без повторной проверки, если хотя бы одно поле заголовка полученного запроса, указанное значением Vary, не совпадает с соответствующим полем исходного запроса, из-за которого ответ был сохранён.
Поля заголовков двух запросов считаются совпадающими тогда и только тогда, когда поля первого запроса можно преобразовать в поля второго любым сочетанием следующих действий:
— добавлением или удалением пробельных символов там, где это допускается синтаксисом поля заголовка; — объединением нескольких строк заголовка с одинаковым именем поля (раздел 5.2 [HTTP]); — нормализацией обоих значений способом, заведомо сохраняющим одинаковую семантику согласно спецификации поля, например перестановкой значений, когда порядок несущественен, или нормализацией регистра для значений, определённых как нечувствительные к нему.
Если после возможной нормализации поле заголовка отсутствует в одном запросе, оно может совпасть с другим запросом только при отсутствии этого поля и там.
Сохранённый ответ со значением поля Vary, содержащим элемент *, всегда считается несовпадающим.
Если совпадают несколько сохранённых ответов, кэшу необходимо выбрать один. Когда указанное поле заголовка запроса имеет известный механизм ранжирования предпочтений, например значения q в Accept и подобных полях, этот механизм МОЖЕТ (MAY) использоваться для выбора предпочтительного ответа. Если такого механизма нет или ответы равноценны, выбирается самый свежий по полю Date согласно разделу 4.
Некоторые ресурсы ошибочно опускают заголовок Vary в ответе по умолчанию, отправляемом, когда запрос не выражает предпочтений. В результате этот ответ выбирается для последующих запросов к ресурсу, даже если доступны более предпочтительные ответы. Если для целевого URI сохранено несколько ответов и один или несколько не содержат Vary, кэшу СЛЕДУЕТ (SHOULD) выбрать самый свежий (раздел 4.2.3) сохранённый ответ с действительным значением Vary.
Если ни один сохранённый ответ не совпадает, кэш не может удовлетворить полученный запрос. Обычно он пересылает запрос исходному серверу, при необходимости добавляя предусловия, описывающие уже сохранённые ответы (раздел 4.3).
4.2. Актуальность
«Актуальный» ответ — ответ, возраст которого ещё не превысил время его актуальности. «Устаревший» ответ — ответ, возраст которого его превысил.
«Время актуальности» ответа — промежуток между его созданием исходным сервером и временем истечения. «Явное время истечения» — момент, после которого, согласно намерению исходного сервера, кэш не может использовать сохранённый ответ без дополнительной проверки. «Эвристическое время истечения» назначается кэшем, когда явное время отсутствует.
«Возраст» ответа — время, прошедшее с момента его создания исходным сервером либо успешной проверки у него.
Актуальный ответ можно использовать для последующих запросов без обращения к исходному серверу, повышая эффективность.
Основной механизм определения актуальности — указание исходным сервером явного будущего времени истечения с помощью поля заголовка Expires (раздел 5.3) или директивы ответа max-age (раздел 5.2.2.1). Обычно исходные серверы назначают такое время, полагая, что представление вряд ли существенно изменится до его наступления.
Если исходный сервер хочет вынудить кэш проверять каждый запрос, он может назначить явное время истечения в прошлом, указав, что ответ уже устарел. Соответствующие спецификации кэши обычно проверяют устаревший ответ перед повторным использованием для последующих запросов (раздел 4.2.4).
Поскольку исходные серверы не всегда предоставляют явное время истечения, при определённых обстоятельствах кэшам разрешено вычислять его эвристически (раздел 4.2.2).
Актуальность ответа определяется так:
response_is_fresh = (freshness_lifetime > current_age)
Значение freshness_lifetime определено в разделе 4.2.1, current_age — в разделе 4.2.3.
Клиенты могут отправлять директивы запроса max-age или min-fresh (раздел 5.2.1), предлагая ограничения расчёта актуальности соответствующего ответа. Однако кэши не обязаны их соблюдать.
При расчёте актуальности для предотвращения распространённых ошибок разбора дат:
— хотя все форматы дат определены как чувствительные к регистру, получателю-кэшу СЛЕДУЕТ (SHOULD) сопоставлять значение поля без учёта регистра; — если внутреннее представление времени получателя-кэша имеет меньшую точность, чем значение HTTP-date, получатель ОБЯЗАН (MUST) внутренне представлять разобранную дату Expires ближайшим временем, равным полученному или предшествующим ему; — получатель-кэш НЕ ДОЛЖЕН (MUST NOT) позволять локальным часовым поясам влиять на вычисление или сравнение возраста либо времени истечения; — получателю-кэшу СЛЕДУЕТ (SHOULD) считать дату с сокращением часового пояса, отличным от GMT, недействительной для расчёта истечения.
Актуальность относится только к работе кэша: ею нельзя принудить пользовательский агент обновить отображение или перезагрузить ресурс. Различие между кэшами и механизмами истории объясняется в разделе 6.
4.2.1. Вычисление времени актуальности
Кэш может вычислить время актуальности ответа freshness_lifetime, проверяя следующие правила и используя первое совпавшее:
— если кэш общий и присутствует директива ответа s-maxage (раздел 5.2.2.10), использовать её значение; — иначе, если присутствует директива ответа max-age (раздел 5.2.2.1), использовать её значение; — иначе, если присутствует поле заголовка ответа Expires (раздел 5.3), использовать его значение за вычетом значения поля заголовка ответа Date; при отсутствии Date используется время получения сообщения согласно разделу 6.6.1 [HTTP]; — иначе явное время истечения отсутствует. Может применяться эвристическое время актуальности; см. раздел 4.2.2.
Расчёт предназначен для уменьшения влияния расхождения часов путём использования, когда возможно, времени, предоставленного исходным сервером.
Если для одной директивы присутствует более одного значения, например две строки Expires или несколько директив Cache-Control: max-age, следует использовать первое значение либо считать ответ устаревшим. Если директивы противоречат друг другу, например присутствуют max-age и no-cache, следует соблюдать наиболее строгую. Кэшам рекомендуется считать устаревшими ответы с недействительными сведениями об актуальности, например директивой max-age с нецелочисленным содержимым.
4.2.2. Эвристическое вычисление актуальности
Поскольку исходные серверы не всегда предоставляют явное время истечения, кэш МОЖЕТ (MAY) назначить эвристическое время, когда явное не указано. Для оценки правдоподобного времени истечения используются алгоритмы, учитывающие значения других полей, например Last-Modified. Спецификация не предписывает конкретных алгоритмов, но ограничивает их результаты в наихудшем случае.
Кэш НЕ ДОЛЖЕН (MUST NOT) использовать эвристики для определения актуальности, если сохранённый ответ содержит явное время истечения. Из-за требований раздела 3 эвристики применимы только к ответам без явной актуальности, коды состояния которых определены как допускающие эвристическое кэширование, например в разделе 15.1 [HTTP], а также к ответам без явной актуальности, явно помеченным как кэшируемые, например директивой ответа public.
В предыдущих спецификациях коды состояния ответов, допускающих эвристическое кэширование, назывались «кэшируемыми по умолчанию».
Если ответ содержит поле заголовка Last-Modified (раздел 8.8.2 [HTTP]), кэшам рекомендуется использовать эвристическое время истечения не больше некоторой доли интервала, прошедшего с указанного времени. Типичным значением этой доли может быть 10%.
Примечание: предыдущая версия спецификации HTTP, раздел 13.9 [RFC2616], запрещала кэшам эвристически вычислять актуальность для URI с компонентами запроса, то есть содержащих «?». На практике это ограничение не было широко реализовано. Поэтому исходным серверам, желающим предотвратить кэширование, рекомендуется отправлять явные директивы, например Cache-Control: no-cache.
4.2.3. Вычисление возраста
Поле заголовка Age передаёт оценочный возраст сообщения ответа, полученного из кэша. Значение Age — оценка кэшем числа секунд, прошедших с момента создания или проверки ответа исходным сервером. Таким образом, оно равно сумме времени пребывания ответа в каждом кэше на пути от исходного сервера и времени передачи по сети.
При расчёте возраста используются:
— age_value: значение поля Age (раздел 5.1) в форме, пригодной для арифметических операций, или 0 при его отсутствии; — date_value: значение поля Date в форме, пригодной для арифметических операций. Определение Date и требования к ответам без него приведены в разделе 6.6.1 [HTTP]; — now: текущее значение часов реализации (раздел 5.6.7 [HTTP]); — request_time: показание часов в момент запроса, приведшего к сохранённому ответу; — response_time: показание часов в момент получения ответа.
Возраст ответа можно вычислить двумя полностью независимыми способами:
1. apparent_age — response_time минус date_value, если часы реализации достаточно хорошо синхронизированы с часами исходного сервера. Отрицательный результат заменяется нулём. 2. corrected_age_value — если все кэши на пути ответа реализуют HTTP/1.1 или более позднюю версию. Кэш ОБЯЗАН (MUST) интерпретировать это значение относительно момента начала запроса, а не момента получения ответа.
apparent_age = max(0, response_time - date_value); response_delay = response_time - request_time; corrected_age_value = age_value + response_delay;
Значение corrected_age_value МОЖНО (MAY) использовать как corrected_initial_age. Если на пути имеются очень старые реализации кэшей, которые могут неправильно вставлять Age, corrected_initial_age можно вычислить более консервативно:
corrected_initial_age = max(apparent_age, corrected_age_value);
Затем current_age сохранённого ответа можно вычислить, добавив к corrected_initial_age время в секундах с последней проверки сохранённого ответа исходным сервером:
resident_time = now - response_time; current_age = corrected_initial_age + resident_time;
4.2.4. Выдача устаревших ответов
«Устаревший» ответ — ответ, для которого имеется явная информация об истечении или разрешено эвристическое вычисление истечения, но который не является актуальным по расчётам раздела 4.2.
Кэш НЕ ДОЛЖЕН (MUST NOT) формировать устаревший ответ, если это запрещено явной директивой протокола, например директивами ответа no-cache или must-revalidate либо применимой директивой ответа s-maxage или proxy-revalidate; см. раздел 5.2.2.
Кэш НЕ ДОЛЖЕН (MUST NOT) формировать устаревший ответ, если он не отключён и такая выдача явно не разрешена клиентом или исходным сервером, например директивой запроса max-stale из раздела 5.2.1, директивами расширения вроде определённых в [RFC5861] или конфигурацией согласно договорённости по внешнему каналу.
4.3. Проверка
Когда в кэше есть один или несколько сохранённых ответов для запрошенного URI, но он не может выдать ни один из них, например из-за неактуальности или невозможности выбора (раздел 4.1), кэш может использовать механизм условного запроса (раздел 13 [HTTP]) в пересылаемом запросе. Это даёт следующему серверу по направлению к источнику возможность выбрать действительный сохранённый ответ с обновлением его метаданных либо заменить сохранённые ответы новым. Процесс называется проверкой или повторной проверкой сохранённого ответа.
4.3.1. Отправка запроса проверки
Формируя условный запрос для проверки, кэш либо начинает с запроса, который пытается удовлетворить, либо, если инициирует запрос самостоятельно, создаёт его из сохранённого ответа, копируя метод, целевой URI и поля заголовка запроса, указанные полем Vary (раздел 4.1).
Затем он дополняет запрос одним или несколькими полями заголовка предусловий. Они содержат метаданные валидатора из сохранённых ответов с тем же URI. Обычно сюда входят только сохранённые ответы с тем же ключом кэша, хотя кэшу разрешено проверять ответ, который он не может выбрать с отправляемыми полями заголовка запроса (раздел 4.1).
Получатели сравнивают поля предусловий, чтобы определить, эквивалентен ли какой-либо сохранённый ответ текущему представлению ресурса.
Один из валидаторов — отметка времени из Last-Modified (раздел 8.8.2 [HTTP]); её можно использовать в If-Modified-Since для проверки ответа либо в If-Unmodified-Since или If-Range для выбора представления, когда клиент ссылается на ранее полученное представление с этой отметкой времени.
Другой валидатор — метка сущности из поля ETag (раздел 8.8.3 [HTTP]). Одну или несколько меток сущностей, обозначающих сохранённые ответы, можно использовать в If-None-Match для проверки ответа либо в If-Match или If-Range для выбора представления, когда клиент ссылается на ранее полученные представления с перечисленными метками.
При формировании условного запроса проверки кэш:
— ОБЯЗАН (MUST) отправлять соответствующие метки сущностей через If-Match, If-None-Match или If-Range, если они были предоставлены в проверяемых сохранённых ответах; — СЛЕДУЕТ (SHOULD) отправлять значение Last-Modified через If-Modified-Since, если запрос не касается поддиапазона, проверяется один сохранённый ответ и он содержит Last-Modified; — МОЖЕТ (MAY) отправлять значение Last-Modified через If-Unmodified-Since или If-Range, если запрос касается поддиапазона, проверяется один сохранённый ответ и он содержит только Last-Modified, но не метку сущности.
В большинстве случаев запросы проверки кэша содержат оба валидатора, даже если метки сущностей явно предпочтительнее: это позволяет старым посредникам, не понимающим предусловия с метками сущностей, ответить надлежащим образом.
4.3.2. Обработка полученного запроса проверки
Каждый клиент в цепочке запросов может иметь собственный кэш, поэтому кэш посредника часто получает условные запросы от других кэшей со стороны клиента. Аналогично некоторые пользовательские агенты применяют условные запросы, чтобы ограничивать передачу данных недавно изменёнными представлениями или завершать передачу частично полученного представления.
Если кэш получает запрос, который может быть удовлетворён повторным использованием сохранённого ответа 200 (OK) или 206 (Partial Content) согласно разделу 4, ему СЛЕДУЕТ (SHOULD) оценить все применимые предусловия из условных заголовков запроса относительно соответствующих валидаторов сохранённого ответа.
Кэш НЕ ДОЛЖЕН (MUST NOT) оценивать условные заголовки, применимые только к исходному серверу; заголовки запроса с семантикой, которую нельзя удовлетворить кэшированным ответом; либо заголовки запроса к целевому ресурсу, для которого нет сохранённых ответов. Такие предусловия, вероятно, предназначены другому серверу по направлению к источнику.
Правильная оценка условных запросов зависит от полученных полей предусловий и их приоритета. Вкратце условные заголовки If-Match и If-Unmodified-Since к кэшу неприменимы, а If-None-Match имеет приоритет над If-Modified-Since. Полная спецификация порядка предусловий приведена в разделе 13.2.2 [HTTP].
Запрос с If-None-Match (раздел 13.1.2 [HTTP]) показывает, что клиент хочет проверить один или несколько собственных сохранённых ответов путём сравнения с ответом, выбранным кэшем согласно разделу 4.
При отсутствии If-None-Match запрос с If-Modified-Since (раздел 13.1.3 [HTTP]) показывает, что клиент хочет проверить один или несколько собственных сохранённых ответов по дате изменения.
Если запрос содержит If-Modified-Since, а в сохранённом ответе нет Last-Modified, кэшу СЛЕДУЕТ (SHOULD) для оценки условия использовать Date сохранённого ответа или, если Date отсутствует, время получения сохранённого ответа.
Кэшу, реализующему частичные ответы на запросы диапазона согласно разделу 14.2 [HTTP], также необходимо оценивать полученное поле If-Range (раздел 13.1.5 [HTTP]) относительно выбранного им ответа.
Когда кэш решает переслать запрос для повторной проверки собственных сохранённых ответов, а запрос содержит список меток сущностей If-None-Match, кэш МОЖЕТ (MAY) объединить полученный список со списком меток собственных сохранённых ответов — актуальных или устаревших — и отправить объединение как заменяющее значение If-None-Match в пересылаемом запросе. Если сохранённый ответ содержит только частичное содержимое, кэш НЕ ДОЛЖЕН (MUST NOT) включать его метку в объединение, кроме случая, когда запрос касается диапазона, который этот частичный ответ полностью удовлетворит. Если ответ на пересланный запрос имеет код 304 (Not Modified), а значение его ETag содержит метку, отсутствующую в списке клиента, кэш ОБЯЗАН (MUST) сформировать для клиента ответ 200 (OK), повторно используя соответствующий сохранённый ответ, обновлённый метаданными ответа 304 (раздел 4.3.4).
4.3.3. Обработка ответа на проверку
Обработка кэшем ответа на условный запрос зависит от кода состояния:
— код 304 (Not Modified) указывает, что сохранённый ответ можно обновить и повторно использовать; см. раздел 4.3.4; — полный ответ, то есть содержащий содержимое, указывает, что ни один из сохранённых ответов, указанных в условном запросе, не подходит. Вместо них кэш ОБЯЗАН (MUST) использовать полный ответ для удовлетворения запроса. Кэш МОЖЕТ (MAY) сохранить полный ответ с учётом действующих ограничений (раздел 3); — если при проверке ответа кэш получает 5xx (Server Error), он может переслать этот ответ запросившему клиенту либо действовать так, будто сервер не ответил. Во втором случае кэш может отправить ранее сохранённый ответ с учётом ограничений на это (раздел 4.2.4) либо повторить запрос проверки.
4.3.4. Обновление актуальности сохранённых ответов при проверке
Получив ответ 304 (Not Modified), кэш должен определить сохранённые ответы, подходящие для обновления предоставленной новой информацией, и обновить их.
Начальный набор составляют сохранённые ответы, которые могли быть выбраны для этого запроса: отвечающие требованиям раздела 4, кроме последнего требования быть актуальными, разрешёнными к выдаче устаревшими или только что проверенными.
Затем начальный набор дополнительно фильтруется по первому подходящему правилу:
— если новый ответ содержит один или несколько строгих валидаторов (раздел 8.8.1 [HTTP]), каждый из них определяет выбранное представление для обновления. Для обновления отбираются все ответы начального набора с одним из тех же строгих валидаторов. Если ни один ответ начального набора не содержит хотя бы одного из этих строгих валидаторов, кэш НЕ ДОЛЖЕН (MUST NOT) использовать новый ответ для обновления сохранённых ответов; — если строгих валидаторов нет, но есть один или несколько слабых и они соответствуют одному из сохранённых ответов начального набора, для обновления выбирается самый свежий из совпавших ответов; — если новый ответ вообще не содержит валидатора, например когда клиент формирует запрос If-Modified-Since из источника, отличного от поля Last-Modified ответа, а начальный набор содержит ровно один сохранённый ответ и тот тоже не имеет валидатора, для обновления выбирается этот ответ.
Для каждого выбранного сохранённого ответа кэш ОБЯЗАН (MUST) обновить поля заголовка полями ответа 304 (Not Modified) согласно разделу 3.2.
4.3.5. Обновление актуальности ответов с помощью HEAD
Ответ на метод HEAD идентичен тому, каким был бы ответ на эквивалентный запрос GET, но без передачи содержимого. Это свойство позволяет аннулировать или обновить кэшированный ответ GET, если более эффективный механизм условного GET недоступен из-за отсутствия валидаторов в сохранённом ответе либо если передача содержимого нежелательна даже при его изменении.
Когда кэш направляет запрос HEAD к целевому URI в сторону исходного сервера и получает ответ 200 (OK), ему СЛЕДУЕТ (SHOULD) обновить или аннулировать каждый свой сохранённый ответ GET, который мог быть выбран для этого запроса (раздел 4.1).
Для каждого такого сохранённого ответа, если значения всех полученных полей валидаторов ETag и Last-Modified совпадают в сохранённом ответе и ответе HEAD и, при наличии Content-Length в ответе HEAD, его значение совпадает с сохранённым ответом, кэшу СЛЕДУЕТ (SHOULD) обновить сохранённый ответ согласно приведённому ниже правилу. Иначе кэшу СЛЕДУЕТ (SHOULD) считать сохранённый ответ устаревшим.
Если кэш обновляет сохранённый ответ метаданными из ответа HEAD, он ОБЯЗАН (MUST) использовать поля заголовка ответа HEAD для обновления сохранённого ответа (раздел 3.2).
4.4. Аннулирование сохранённых ответов
Поскольку небезопасные методы запроса (раздел 9.2.1 [HTTP]), такие как PUT, POST или DELETE, могут изменять состояние исходного сервера, промежуточные кэши обязаны аннулировать сохранённые ответы для поддержания их содержимого в актуальном состоянии.
Получив неошибочный код состояния в ответ на запрос с небезопасным методом, включая методы с неизвестной безопасностью, кэш ОБЯЗАН (MUST) аннулировать целевой URI (раздел 7.1 [HTTP]).
При получении такого неошибочного ответа кэш МОЖЕТ (MAY) аннулировать другие URI. В частности, кандидатами являются URI из полей ответа Location и Content-Location, если они присутствуют; другие URI могут обнаруживаться механизмами, не определёнными документом. Однако кэш НЕ ДОЛЖЕН (MUST NOT) вызывать аннулирование в этих условиях, если origin аннулируемого URI (раздел 4.3.1 [HTTP]) отличается от origin целевого URI (раздел 7.1 [HTTP]). Это помогает предотвращать атаки типа «отказ в обслуживании».
«Аннулировать» означает, что кэш либо удаляет все сохранённые ответы, целевой URI которых совпадает с заданным, либо помечает их как недействительные и требующие обязательной проверки перед отправкой в ответ на последующий запрос.
«Неошибочный ответ» — ответ с кодом состояния 2xx (Successful) или 3xx (Redirection).
Это не гарантирует глобального аннулирования всех подходящих ответов: запрос, изменяющий состояние, аннулирует ответы только в тех кэшах, через которые проходит.
5. Определения полей
В разделе определены синтаксис и семантика полей HTTP, связанных с кэшированием.
5.1. Age
Поле заголовка ответа Age передаёт оценку отправителем времени, прошедшего с момента создания ответа или его успешной проверки на исходном сервере. Значения Age вычисляются согласно разделу 4.2.3.
Age = delta-seconds
Значение Age — неотрицательное целое число, представляющее время в секундах (раздел 1.2.2).
Хотя оно определено как поле заголовка с единственным значением, кэшу, встретившему сообщение со списочным значением Age, СЛЕДУЕТ (SHOULD) использовать первый элемент и отбросить последующие.
Если значение поля после отбрасывания дополнительных элементов недействительно, например содержит что-либо кроме неотрицательного целого числа, кэшу СЛЕДУЕТ (SHOULD) игнорировать поле.
Наличие заголовка Age означает, что исходный сервер не создавал и не проверял ответ для данного запроса. Однако отсутствие Age не означает, что обращение к исходному серверу состоялось.
5.2. Cache-Control
Поле заголовка Cache-Control перечисляет директивы для кэшей вдоль цепочки запроса и ответа. Директивы кэша однонаправленны: наличие директивы в запросе не означает её присутствия или копирования в ответ.
Сведения об обработке директив Cache-Control, определённых в других документах, приведены в разделе 5.2.3.
Прокси, реализующий кэш или нет, ОБЯЗАН (MUST) передавать директивы кэша в пересылаемых сообщениях независимо от их значимости для этого приложения, поскольку они могут относиться ко всем получателям вдоль цепочки запроса и ответа. Адресовать директиву конкретному кэшу невозможно.
Директивы кэша обозначаются токеном, сравниваемым без учёта регистра, и могут иметь необязательный аргумент в синтаксисе token или quoted-string. Для определённых ниже директив с аргументами получателям следует принимать обе формы, даже если при формировании требуется определённая форма.
Cache-Control = #cache-directive cache-directive = token [ "=" ( token / quoted-string ) ]
Для определённых ниже директив кэша аргументы не определены и не допускаются, если не указано иное.
5.2.1. Директивы запроса
Раздел определяет директивы кэша в запросе. Они носят рекомендательный характер: кэши МОГУТ (MAY) их реализовать, но не обязаны.
5.2.1.1. max-age
Синтаксис аргумента: delta-seconds (раздел 1.2.2).
Директива запроса max-age указывает, что клиент предпочитает ответ с возрастом не больше заданного числа секунд. Если также не присутствует директива запроса max-stale, клиент не желает получать устаревший ответ.
Директива использует форму аргумента token: например, max-age=5, а не max-age="5". Отправитель НЕ ДОЛЖЕН (MUST NOT) формировать форму quoted-string.
5.2.1.2. max-stale
Синтаксис аргумента: delta-seconds (раздел 1.2.2).
Директива запроса max-stale указывает, что клиент принимает ответ, срок актуальности которого истёк. Если задано значение, клиент готов принять ответ, срок актуальности которого превышен не более чем на указанное число секунд. Если значение max-stale не задано, клиент принимает устаревший ответ любого возраста.
Директива использует форму аргумента token: например, max-stale=10, а не max-stale="10". Отправитель НЕ ДОЛЖЕН (MUST NOT) формировать quoted-string.
5.2.1.3. min-fresh
Синтаксис аргумента: delta-seconds (раздел 1.2.2).
Директива запроса min-fresh указывает, что клиент предпочитает ответ, время актуальности которого не меньше суммы текущего возраста и указанного времени в секундах. Иными словами, клиент желает получить ответ, который останется актуальным не менее указанного числа секунд.
Директива использует форму аргумента token: например, min-fresh=20, а не min-fresh="20". Отправитель НЕ ДОЛЖЕН (MUST NOT) формировать quoted-string.
5.2.1.4. no-cache
Директива запроса no-cache указывает, что клиент предпочитает не использовать сохранённый ответ для удовлетворения запроса без успешной проверки исходным сервером.
5.2.1.5. no-store
Директива запроса no-store указывает, что кэш НЕ ДОЛЖЕН (MUST NOT) сохранять какую-либо часть этого запроса или любого ответа на него. Она применяется к частным и общим кэшам. «НЕ ДОЛЖЕН сохранять» здесь означает, что кэш НЕ ДОЛЖЕН (MUST NOT) намеренно записывать информацию в энергонезависимое хранилище и ОБЯЗАН (MUST) приложить все разумные усилия для удаления информации из энергозависимого хранилища как можно скорее после её пересылки.
Эта директива не является надёжным или достаточным механизмом обеспечения конфиденциальности. В частности, злонамеренные или скомпрометированные кэши могут не распознать её или не соблюдать, а сети связи могут быть уязвимы к прослушиванию.
Если запрос с этой директивой удовлетворён из кэша, директива no-store запроса не применяется к уже сохранённому ответу.
5.2.1.6. no-transform
Директива запроса no-transform указывает, что клиент просит посредников не преобразовывать содержимое согласно разделу 7.7 [HTTP].
5.2.1.7. only-if-cached
Директива запроса only-if-cached указывает, что клиент желает получить только сохранённый ответ. Кэшам, соблюдающим эту директиву, СЛЕДУЕТ (SHOULD) отвечать либо сохранённым ответом, соответствующим остальным ограничениям запроса, либо кодом состояния 504 (Gateway Timeout).
5.2.2. Директивы ответа
В разделе определены директивы кэша в ответе. Кэш ОБЯЗАН (MUST) соблюдать определённые здесь директивы Cache-Control.
5.2.2.1. max-age
Синтаксис аргумента: delta-seconds (раздел 1.2.2).
Директива ответа max-age указывает, что ответ считается устаревшим, когда его возраст превышает указанное число секунд.
Директива использует форму аргумента token: например, max-age=5, а не max-age="5". Отправитель НЕ ДОЛЖЕН (MUST NOT) формировать quoted-string.
5.2.2.2. must-revalidate
Директива ответа must-revalidate указывает, что после устаревания ответа кэш НЕ ДОЛЖЕН (MUST NOT) повторно использовать его для другого запроса до успешной проверки у исходного сервера согласно разделу 4.3.
Директива must-revalidate необходима для надёжной работы некоторых возможностей протокола. Кэш НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ НЕ ДОЛЖЕН (MUST NOT) игнорировать её; в частности, если кэш отключён, он ОБЯЗАН (MUST) сформировать ответ об ошибке вместо повторного использования устаревшего ответа. Сформированному коду состояния СЛЕДУЕТ (SHOULD) быть 504 (Gateway Timeout), если другой код ошибки не подходит лучше.
Серверам следует использовать must-revalidate тогда и только тогда, когда отсутствие проверки запроса может привести к неправильной работе, например к незаметно невыполненной финансовой транзакции.
Директива must-revalidate также разрешает общему кэшу повторно использовать ответ на запрос с полем заголовка Authorization (раздел 11.6.2 [HTTP]) при соблюдении приведённого требования повторной проверки (раздел 3.5).
5.2.2.3. must-understand
Директива ответа must-understand ограничивает кэширование ответа кэшами, которые понимают и соблюдают требования к его коду состояния.
Ответу с директивой must-understand СЛЕДУЕТ (SHOULD) также содержать no-store. Получив ответ с must-understand, кэшу, реализующему эту директиву, СЛЕДУЕТ (SHOULD) игнорировать no-store, если он понимает и реализует требования к кэшированию для данного кода состояния.
5.2.2.4. no-cache
Синтаксис аргумента: #field-name.
Директива ответа no-cache в неквалифицированной форме, без аргумента, указывает, что ответ НЕ ДОЛЖЕН (MUST NOT) использоваться для другого запроса без пересылки для проверки и получения успешного ответа; см. раздел 4.3.
Это позволяет исходному серверу предотвратить использование ответа для запроса без обращения к нему, в том числе кэшами, настроенными на выдачу устаревших ответов.
Квалифицированная форма no-cache с аргументом, перечисляющим одно или несколько имён полей, указывает, что кэш МОЖЕТ (MAY) использовать ответ для последующего запроса при соблюдении остальных ограничений кэширования, если перечисленные поля заголовка исключены из последующего ответа либо последующий ответ успешно повторно проверен на исходном сервере с обновлением или удалением этих полей. Это позволяет исходному серверу предотвратить повторное использование определённых полей заголовка, разрешив кэширование остальной части ответа.
Указанные имена полей не ограничены набором полей заголовков этой спецификации. Имена полей нечувствительны к регистру.
Директива использует форму аргумента quoted-string. Отправителю НЕ СЛЕДУЕТ (SHOULD NOT) формировать форму token, даже если для списка из одного элемента кавычки кажутся ненужными.
Примечание: кэши часто обрабатывают квалифицированную форму так, будто получена неквалифицированная директива no-cache; специальная обработка квалифицированной формы не получила широкого распространения.
5.2.2.5. no-store
Директива ответа no-store указывает, что кэш НЕ ДОЛЖЕН (MUST NOT) сохранять какую-либо часть непосредственно связанного запроса или ответа и НЕ ДОЛЖЕН (MUST NOT) использовать ответ для какого-либо другого запроса.
Директива применяется к частным и общим кэшам. «НЕ ДОЛЖЕН сохранять» означает, что кэш НЕ ДОЛЖЕН (MUST NOT) намеренно записывать информацию в энергонезависимое хранилище и ОБЯЗАН (MUST) приложить все разумные усилия для удаления информации из энергозависимого хранилища как можно скорее после пересылки.
Эта директива не является надёжным или достаточным механизмом обеспечения конфиденциальности. В частности, злонамеренные или скомпрометированные кэши могут не распознать её или не соблюдать, а сети связи могут быть уязвимы к прослушиванию.
При определённых обстоятельствах директива must-understand переопределяет no-store; см. раздел 5.2.2.3.
5.2.2.6. no-transform
Директива ответа no-transform указывает, что посредник, независимо от реализации кэша, НЕ ДОЛЖЕН (MUST NOT) преобразовывать содержимое согласно разделу 7.7 [HTTP].
5.2.2.7. private
Синтаксис аргумента: #field-name.
Неквалифицированная директива ответа private указывает, что общий кэш НЕ ДОЛЖЕН (MUST NOT) сохранять ответ: он предназначен одному пользователю. Она также указывает, что частный кэш МОЖЕТ (MAY) сохранить ответ с учётом ограничений раздела 3, даже если в иных условиях частный кэш не мог бы кэшировать ответ эвристически.
Если присутствует квалифицированная директива private с аргументом, перечисляющим одно или несколько имён полей, ограничение одним пользователем относится только к перечисленным полям: общий кэш НЕ ДОЛЖЕН (MUST NOT) сохранять перечисленные поля заголовка, если они присутствуют в исходном ответе, но МОЖЕТ (MAY) сохранить остальную часть сообщения без них с учётом ограничений раздела 3.
Указанные имена не ограничены набором полей этой спецификации и нечувствительны к регистру.
Директива использует форму аргумента quoted-string. Отправителю НЕ СЛЕДУЕТ (SHOULD NOT) формировать token, даже если для списка из одного элемента кавычки кажутся ненужными.
Примечание: слово private здесь управляет только местом сохранения ответа и не может обеспечить конфиденциальность содержимого сообщения. Кроме того, кэши часто обрабатывают квалифицированную форму так, будто получена неквалифицированная private; специальная обработка квалифицированной формы не получила широкого распространения.
5.2.2.8. proxy-revalidate
Директива ответа proxy-revalidate указывает, что после устаревания ответа общий кэш НЕ ДОЛЖЕН (MUST NOT) повторно использовать его для другого запроса до успешной проверки исходным сервером согласно разделу 4.3. Это аналогично must-revalidate (раздел 5.2.2.2), за исключением того, что proxy-revalidate не применяется к частным кэшам.
Само по себе proxy-revalidate не означает, что ответ допускает кэширование. Например, его можно сочетать с public (раздел 5.2.2.9), разрешая кэшировать ответ и требуя повторной проверки при устаревании только от общего кэша.
5.2.2.9. public
Директива ответа public указывает, что кэш МОЖЕТ (MAY) сохранить ответ, даже если иначе это было бы запрещено, с учётом ограничений раздела 3. Иными словами, public явно отмечает ответ как кэшируемый. Например, public разрешает общему кэшу повторно использовать ответ на запрос с полем Authorization (раздел 3.5).
Добавлять public к ответу, который уже допускает кэширование согласно разделу 3, не требуется.
Если ответ с public не содержит явных сведений об актуальности, он допускает эвристическое кэширование (раздел 4.2.2).
5.2.2.10. s-maxage
Синтаксис аргумента: delta-seconds (раздел 1.2.2).
Директива ответа s-maxage указывает, что для общего кэша максимальный возраст, заданный этой директивой, переопределяет максимальный возраст из директивы max-age или поля заголовка Expires.
Для общего кэша s-maxage включает семантику директивы ответа proxy-revalidate (раздел 5.2.2.8). Общий кэш НЕ ДОЛЖЕН (MUST NOT) повторно использовать устаревший ответ с s-maxage для другого запроса до успешной проверки исходным сервером согласно разделу 4.3. Эта директива также разрешает общему кэшу повторно использовать ответ на запрос с полем Authorization при соблюдении приведённых требований к максимальному возрасту и повторной проверке (раздел 3.5).
Директива использует форму аргумента token: например, s-maxage=10, а не s-maxage="10". Отправитель НЕ ДОЛЖЕН (MUST NOT) формировать quoted-string.
5.2.3. Директивы расширения
Поле заголовка Cache-Control можно расширять одной или несколькими директивами расширения кэша. Кэш ОБЯЗАН (MUST) игнорировать нераспознанные директивы кэша.
Информационные расширения, не требующие изменения поведения кэша, можно добавлять без изменения семантики других директив.
Поведенческие расширения предназначены для работы как модификаторы существующих основных директив кэша. Передаются и новая, и старая директива: приложения, не понимающие новую, по умолчанию применяют поведение старой; понимающие новую распознают её как изменяющую требования, связанные со старой. Так существующие директивы можно расширять, не нарушая работу развёрнутых кэшей.
Например, рассмотрим гипотетическую новую директиву ответа community, изменяющую private: помимо частных кэшей сохранять ответ разрешено только кэшу, общему для участников указанного сообщества. Исходный сервер, желающий разрешить сообществу UCI использовать в своих общих кэшах ответ, который иначе был бы частным, может включить:
Cache-Control: private, community="UCI"
Кэш, распознающий директиву community, может расширить своё поведение согласно этому расширению. Кэш, не распознающий community, проигнорирует её и будет соблюдать private.
При определении новых директив расширения следует рассмотреть:
— значение многократного указания директивы; — значение присутствия аргумента, если директива его не принимает; — значение отсутствия аргумента, если он обязателен; — относится ли директива только к запросам, только к ответам или может использоваться в обоих случаях.
5.2.4. Реестр директив кэша
«Реестр директив кэша протокола передачи гипертекста HTTP» определяет пространство имён директив кэша. Он создан и поддерживается по адресу https://www.iana.org/assignments/http-cache-directives.
Регистрация ОБЯЗАТЕЛЬНО (MUST) включает имя директивы кэша и указатель на текст спецификации.
Добавление значений в пространство имён требует проверки IETF (раздел 4.8 [RFC8126]).
5.3. Expires
Поле заголовка ответа Expires задаёт дату и время, после которых ответ считается устаревшим. Дополнительное обсуждение модели актуальности приведено в разделе 4.2.
Наличие Expires не означает, что исходный ресурс изменится или перестанет существовать в это время, до него или после него.
Значение Expires — временная отметка HTTP-date согласно разделу 5.6.7 [HTTP]. Требования к разбору, специфичные для кэшей, см. также в разделе 4.2.
Expires = HTTP-date
Пример: Expires: Thu, 01 Dec 1994 16:00:00 GMT
Получатель-кэш ОБЯЗАН (MUST) интерпретировать недействительные форматы дат, особенно значение «0», как время в прошлом, то есть уже истёкшее.
Если ответ содержит Cache-Control с директивой max-age (раздел 5.2.2.1), получатель ОБЯЗАН (MUST) игнорировать Expires. Аналогично, если ответ содержит s-maxage (раздел 5.2.2.10), получатель — общий кэш — ОБЯЗАН (MUST) игнорировать Expires. В обоих случаях значение Expires предназначено только для получателей, ещё не реализовавших Cache-Control.
Исходный сервер без часов (раздел 5.6.7 [HTTP]) НЕ ДОЛЖЕН (MUST NOT) формировать Expires, если значение не представляет фиксированное время в прошлом, всегда истёкшее, и при этом не было связано с ресурсом системой, имеющей часы.
Исторически HTTP требовал, чтобы значение Expires находилось не более чем на год в будущем. Хотя более длительные сроки актуальности больше не запрещены, продемонстрировано, что чрезвычайно большие значения вызывают проблемы, например переполнение часов из-за использования 32-битовых целых чисел для времени; многие кэши удалят ответ гораздо раньше.
5.4. Pragma
Поле заголовка запроса Pragma было определено для кэшей HTTP/1.0, чтобы клиенты могли указать запрос no-cache, поскольку Cache-Control не был определён до HTTP/1.1.
Сейчас поддержка Cache-Control широко распространена, поэтому настоящая спецификация объявляет Pragma устаревшим.
Примечание: поскольку значение Pragma: no-cache в ответах никогда не определялось, оно не является надёжной заменой Cache-Control: no-cache в ответах.
5.5. Warning
Поле заголовка Warning использовалось для передачи дополнительных сведений о состоянии или преобразовании сообщения, которые могли не отражаться кодом состояния. Спецификация прекращает его использование, поскольку оно редко формируется или показывается пользователям. Сведения, которые оно передавало, можно получить из других полей, например Age.
6. Взаимосвязь с приложениями и другими кэшами
Приложения, использующие HTTP, часто определяют дополнительные формы кэширования. Например, веб-браузеры часто имеют механизмы истории, такие как кнопка «Назад», позволяющие повторно показать представление, полученное ранее в сеансе.
Аналогично некоторые веб-браузеры кэшируют изображения и другие ресурсы в пределах просмотра страницы; они могут соблюдать семантику HTTP-кэширования или не соблюдать её.
Требования спецификации не обязательно применимы к тому, как приложения используют данные после извлечения из HTTP-кэша. Например, механизм истории может показать предыдущее представление даже после истечения его срока, а приложение может иным образом использовать кэшированные данные после окончания их актуальности.
Спецификация не запрещает приложению учитывать HTTP-кэширование: например, механизм истории может сообщить пользователю об устаревшем представлении или соблюдать директивы кэша, такие как Cache-Control: no-store.
Однако когда приложение кэширует данные, не делая это очевидным для пользователя и не предоставляя ему простого управления, ему настоятельно рекомендуется определить своё поведение относительно директив HTTP-кэша так, чтобы не удивлять авторов, ожидающих соблюдения семантики кэширования. Например, может быть разумно определить кэш приложения «над» HTTP, разрешающий повторно использовать ответ с Cache-Control: no-store для запросов, непосредственно связанных с получившим его запросом, таких как запросы при той же загрузке страницы. Но возможность повторно использовать его для запросов, никак не связанных с исходным, вероятно, удивила бы и запутала пользователей и авторов.
7. Вопросы безопасности
Раздел информирует разработчиков, поставщиков информации и пользователей об известных проблемах безопасности, специфичных для HTTP-кэширования. Более общие вопросы рассмотрены в HTTP/1.1 (раздел 11 [HTTP/1.1]) и «Семантике HTTP» (раздел 17 [HTTP]).
Кэши создают дополнительную поверхность атаки, поскольку их содержимое привлекательно для злоумышленников. Так как содержимое кэша сохраняется после завершения HTTP-запроса, атака на кэш может раскрыть информацию спустя долгое время после того, как пользователь считает её удалённой из сети. Поэтому содержимое кэша необходимо защищать как конфиденциальную информацию.
В частности, поскольку частные кэши ограничены одним пользователем, их можно использовать для восстановления его действий. Поэтому важно, чтобы пользовательские агенты позволяли конечным пользователям управлять ими, например удалять сохранённые ответы для некоторых или всех исходных серверов.
7.1. Отравление кэша
Сохранение вредоносного содержимого в кэше может расширить воздействие злоумышленника на многих пользователей. Такие атаки «отравления кэша» происходят, когда злоумышленник использует недостатки реализации, повышенные привилегии или другие методы для помещения ответа в кэш. Особенно эффективно использование общих кэшей для распространения вредоносного содержимого многим клиентам.
Распространённый вектор атаки — эксплуатация различий в разборе сообщений прокси и пользовательскими агентами; требования к HTTP/1.1 приведены в разделе 6.3 [HTTP/1.1].
7.2. Атаки по времени
Поскольку одна из основных задач кэша — оптимизация производительности, его использование может приводить к «утечке» сведений о ранее запрошенных ресурсах.
Например, пользователь посещает сайт, браузер кэширует некоторые ответы, а затем пользователь переходит на второй сайт. Второй сайт может попытаться загрузить ответы, о существовании которых на первом сайте ему известно. Если загрузка быстрая, можно предположить, что пользователь посещал первый сайт или даже определённую его страницу.
Такие «атаки по времени» можно смягчить, добавив в ключ кэша дополнительные сведения, например идентичность ссылающегося сайта для предотвращения описанной атаки. Иногда это называется «двойным ключом».
7.3. Кэширование конфиденциальной информации
Недостатки реализации и развёртывания, часто вызванные непониманием работы кэша, могут приводить к кэшированию информации, считающейся конфиденциальной, например учётных данных аутентификации, и её раскрытию неавторизованным лицам.
Поле заголовка ответа Set-Cookie [COOKIE] не препятствует кэшированию: кэшируемый ответ с Set-Cookie может использоваться и часто используется для последующих запросов к кэшам. Серверам, желающим управлять кэшированием таких ответов, рекомендуется отправлять соответствующие поля заголовка ответа Cache-Control.
8. Вопросы IANA
Орган управления изменениями для следующих регистраций: «IETF (iesg@ietf.org) — Internet Engineering Task Force».
8.1. Регистрация имён полей
IANA обновила «Реестр имён полей протокола передачи гипертекста HTTP» по адресу https://www.iana.org/assignments/http-fields согласно разделу 18.4 [HTTP], включив указанные ниже имена полей:
Имя поля Статус Раздел Age постоянный 5.1 Cache-Control постоянный 5.2 Expires постоянный 5.3 Pragma устаревший 5.4 Warning отменённый 5.5
Таблица 1.
8.2. Регистрация директив кэша
IANA обновила «Реестр директив кэша протокола передачи гипертекста HTTP» по адресу https://www.iana.org/assignments/http-cache-directives, включив процедуру регистрации по разделу 5.2.4 и следующие имена директив:
Директива кэша Раздел max-age 5.2.1.1, 5.2.2.1 max-stale 5.2.1.2 min-fresh 5.2.1.3 must-revalidate 5.2.2.2 must-understand 5.2.2.3 no-cache 5.2.1.4, 5.2.2.4 no-store 5.2.1.5, 5.2.2.5 no-transform 5.2.1.6, 5.2.2.6 only-if-cached 5.2.1.7 private 5.2.2.7 proxy-revalidate 5.2.2.8 public 5.2.2.9 s-maxage 5.2.2.10
Таблица 2.
8.3. Реестр кодов предупреждений
IANA добавила следующее примечание в реестр кодов предупреждений HTTP по адресу https://www.iana.org/assignments/http-warn-codes, указав, что Warning отменён:
«Поле заголовка Warning и используемые им коды предупреждений отменены для HTTP согласно [RFC9111]».
9. Ссылки
9.1. Нормативные ссылки
[HTTP] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP Semantics", STD 97, RFC 9110,
DOI 10.17487/RFC9110, June 2022,
<https://www.rfc-editor.org/info/rfc9110>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", STD 68, RFC 5234,
DOI 10.17487/RFC5234, January 2008,
<https://www.rfc-editor.org/info/rfc5234>.
[RFC7405] Kyzivat, P., "Case-Sensitive String Support in ABNF",
RFC 7405, DOI 10.17487/RFC7405, December 2014,
<https://www.rfc-editor.org/info/rfc7405>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
9.2. Информационные ссылки
[COOKIE] Barth, A., "HTTP State Management Mechanism", RFC 6265,
DOI 10.17487/RFC6265, April 2011,
<https://www.rfc-editor.org/info/rfc6265>.
[HTTP/1.1] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP/1.1", STD 99, RFC 9112, DOI 10.17487/RFC9112,
June 2022, <https://www.rfc-editor.org/info/rfc9112>.
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
Transfer Protocol -- HTTP/1.1", RFC 2616,
DOI 10.17487/RFC2616, June 1999,
<https://www.rfc-editor.org/info/rfc2616>.
[RFC5861] Nottingham, M., "HTTP Cache-Control Extensions for Stale
Content", RFC 5861, DOI 10.17487/RFC5861, May 2010,
<https://www.rfc-editor.org/info/rfc5861>.
[RFC7234] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "Hypertext Transfer Protocol (HTTP/1.1): Caching",
RFC 7234, DOI 10.17487/RFC7234, June 2014,
<https://www.rfc-editor.org/info/rfc7234>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
Writing an IANA Considerations Section in RFCs", BCP 26,
RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>.
Приложение A. Сводная грамматика ABNF
В приведённой ниже сводной грамматике правила списков раскрыты согласно разделу 5.6.1 [HTTP].
Age = delta-seconds Cache-Control = [ cache-directive *( OWS "," OWS cache-directive ) ] Expires = HTTP-date HTTP-date = <HTTP-date, см. [HTTP], раздел 5.6.7> OWS = <OWS, см. [HTTP], раздел 5.6.3> cache-directive = token [ "=" ( token / quoted-string ) ] delta-seconds = 1*DIGIT field-name = <field-name, см. [HTTP], раздел 5.1> quoted-string = <quoted-string, см. [HTTP], раздел 5.6.4> token = <token, см. [HTTP], раздел 5.6.2>
Приложение B. Изменения относительно RFC 7234
Уточнена обработка повторяющихся и противоречащих директив кэша (раздел 4.2.1).
Аннулирование кэша для URI в полях Location и Content-Location больше не обязательно, но по-прежнему допускается (раздел 4.4).
Аннулирование кэша для URI в полях Location и Content-Location запрещено при различии origin; ранее ограничение касалось хоста (раздел 4.4).
Уточнена обработка недействительных и нескольких значений поля Age (раздел 5.1).
Для некоторых директив этой спецификации усилены запреты на формирование значений в кавычках, поскольку это приводило к проблемам совместимости. Получатели директив расширения больше не обязаны принимать обе формы, token и quoted-string, но по-прежнему должны правильно разбирать их для неизвестных расширений (раздел 5.2).
Уточнены директивы public и private: они не делают ответы пригодными для повторного использования при любых условиях (раздел 5.2.2).
Введена директива must-understand; кэши больше не обязаны понимать семантику новых кодов состояния ответа, если она отсутствует (раздел 5.2.2.3).
Заголовок ответа Warning отменён. Значительную часть передававшихся им сведений можно получить при рассмотрении ответа; оставшиеся сведения, хотя и потенциально полезные, носили исключительно рекомендательный характер. На практике кэши и посредники Warning не добавляли (раздел 5.5).
Благодарности
См. приложение «Благодарности» документа [HTTP], которое также относится к настоящему документу.
Алфавитный указатель
A C E F G H M N O P S V W
A
возраст раздел 4.2
Age поле заголовка *_раздел 5.1_*
C
кэш раздел 1
ключ кэша раздел 2; раздел 2
Cache-Control поле заголовка *_раздел 5.2_*
объединённые запросы раздел 4
E
Expires поле заголовка *_раздел 5.3_*
явное время истечения раздел 4.2
F
Поля
Age *_раздел 5.1_*; *_раздел 5.1_*
Cache-Control *_раздел 5.2_*
Expires *_раздел 5.3_*; *_раздел 5.3_*
Pragma *_раздел 5.4_*; *_раздел 5.4_*
Warning *_раздел 5.5_*
свежий раздел 4.2
время свежести раздел 4.2
G
Грамматика
Age *_раздел 5.1_*
Cache-Control *_раздел 5.2_*
DIGIT *_раздел 1.2_*
Expires *_раздел 5.3_*
cache-directive *_раздел 5.2_*
delta-seconds *_раздел 1.2.2_*
H
Поля заголовков
Age *_раздел 5.1_*; *_раздел 5.1_*
Cache-Control *_раздел 5.2_*
Expires *_раздел 5.3_*; *_раздел 5.3_*
Pragma *_раздел 5.4_*; *_раздел 5.4_*
Warning *_раздел 5.5_*
эвристическое время истечения раздел 4.2
кэшируемый эвристически раздел 4.2.2
M
max-age (директива кэша) *_раздел 5.2.1.1_*;
*_раздел 5.2.2.1_*
max-устаревший (директива кэша) *_раздел 5.2.1.2_*
min-свежий (директива кэша) *_раздел 5.2.1.3_*
must-revalidate (директива кэша) *_раздел 5.2.2.2_*
must-understand (директива кэша) *_раздел 5.2.2.3_*
N
no-cache (директива кэша) *_раздел 5.2.1.4_*;
*_раздел 5.2.2.4_*
no-store (директива кэша) *_раздел 5.2.1.5_*;
*_раздел 5.2.2.5_*
no-transform (директива кэша) *_раздел 5.2.1.6_*;
*_раздел 5.2.2.6_*
O
only-if-cached (директива кэша) *_раздел 5.2.1.7_*
P
Pragma поле заголовка *_раздел 5.4_*
private (директива кэша) *_раздел 5.2.2.7_*
частный кэш раздел 1
proxy-revalidate (директива кэша) *_раздел 5.2.2.8_*
public (директива кэша) *_раздел 5.2.2.9_*
S
s-maxage (директива кэша) *_раздел 5.2.2.10_*
общий кэш раздел 1
устаревший раздел 4.2
V
валидатор раздел 4.3.1
W
Warning поле заголовка *_раздел 5.5_*
Адреса авторов
Roy T. Fielding (editor) Adobe 345 Park Ave San Jose, CA 95110 United States of America Email: fielding@gbiv.com URI: https://roy.gbiv.com/
Mark Nottingham (editor) Fastly Prahran Australia Email: mnot@mnot.net URI: https://www.mnot.net/
Julian Reschke (editor) greenbytes GmbH Hafenweg 16 48155 Münster Germany Email: julian.reschke@greenbytes.de URI: https://greenbytes.de/tech/webdav/
Перевод: RFCNET · rfcnet.ru
Original copyright notice
Copyright Notice
Copyright (c) 2022 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must
include Revised BSD License text as described in Section 4.e of the
Trust Legal Provisions and are provided without warranty as described
in the Revised BSD License.
This document may contain material from IETF Documents or IETF
Contributions published or made publicly available before November
10, 2008. The person(s) controlling the copyright in some of this
material may not have granted the IETF Trust the right to allow
modifications of such material outside the IETF Standards Process.
Without obtaining an adequate license from the person(s) controlling
the copyright in such materials, this document may not be modified
outside the IETF Standards Process, and derivative works of it may
not be created outside the IETF Standards Process, except to format
it for publication as an RFC or to translate it into languages other
than English.
Неофициальный перевод. При расхождениях см. оригинал.