RFC 7232 | Протокол передачи гипертекста (HTTP/1.1): условные запросы

Аннотация

Протокол передачи гипертекста (HTTP) — это протокол уровня приложений без сохранения состояния для распределенных, совместных гипертекстовых информационных систем. В этом документе определяются условные запросы HTTP/1.1, в том числе поля заголовка метаданных для указания изменений состояния, поля заголовка запроса для создания предварительных условий для такого состояния и правила построения ответов на условный запрос, когда одно или несколько предварительных условий оцениваются как ложные.

Читать оригинальную версию документа на английском языке RFC 7232 PDF

Оглавление

1. Введение
1.1. Соответствие и обработка ошибок
1.2. Синтаксическая нотация
2. Валидаторы
2.1. Слабые против сильных
2.2. Заголовок Last-Modified (Последнее изменение)
2.2.1. Генерация
2.2.2. Сравнение
2.3. Заголовок ETag
2.3.1. Генерация
2.3.2. Сравнение
2.3.3. Пример: Entity-Tags (теги сущностей), изменяющиеся на ресурсах с согласованным содержимым
2.4. Когда использовать Entity-Tags (теги сущностей) и даты Last-Modified (последнего изменения)
3. Поля заголовка предварительного условия
3.1. If-Match
3.2. If-None-Match
3.3. If-Modified-Since
3.4. If-Unmodified-Since
3.5. If-Range
4. Определения кода состояния
4.1. Код 304 — Не модифицировано
4.2. Код 412 — Не выполнено предварительное условие
5. Оценка
6. Приоритет
7. Соображения IANA
7.1. Регистрация кода статуса
7.2. Регистрация поля заголовка
8. Вопросы безопасности
9. Благодарности
10. Ссылки
10.1. Нормативные ссылки
10.2. Информационные ссылки
Приложение A. Изменения по сравнению с RFC 2616
Приложение B. Импортированный ABNF
Приложение C. Собранный ABNF
Индекс
Адреса авторов

1. Введение

Условными запросами являются HTTP-запросы [RFC7231 #], которые включают в себя одно или несколько полей заголовка, указывающих предварительное условие, которое должно быть проверено перед применением семантики метода к целевому ресурсу. Этот документ определяет механизмы условного запроса HTTP/1.1 с точки зрения архитектуры, синтаксической нотации и критериев соответствия, определенных в [RFC7230 #].

Условные запросы GET являются наиболее эффективным механизмом обновления кэша HTTP [RFC7234 #]. Условные обозначения также могут применяться к методам изменения состояния, таким как PUT и DELETE, для предотвращения проблемы «lost update» (потерянного обновления): один клиент случайно перезаписывает работу другого клиента, который работает параллельно.

Условные предварительные условия запроса основаны на состоянии целевого ресурса в целом (его текущем наборе значений) или состоянии, наблюдаемом в ранее полученном представлении (одно значение в этом наборе). Ресурс может иметь несколько текущих представлений, каждое из которых имеет собственное наблюдаемое состояние. Механизмы условных запросов предполагают, что сопоставление запросов с «selected representation» (выбранным представлением) (раздел 3 [RFC7231 #]) будет согласованным во времени, если сервер намеревается использовать условные преимущества. В любом случае, если сопоставление является непоследовательным, и сервер не может выбрать соответствующее представление, то никакого вреда не будет, если предварительное условие оценивается как ложное.

Условные предварительные условия запроса, определенные в настоящей спецификации (раздел 3), оцениваются, когда они применимы к получателю (раздел 5), в соответствии с их порядком приоритета (раздел 6).

1.1. Соответствие и обработка ошибок

Ключевые слова «ОБЯЗАН — MUST», «НЕ ОБЯЗАН — MUST NOT», «ТРЕБУЕТСЯ — REQUIRED», «ДОЛЖЕН — SHALL», «НЕ ДОЛЖЕН — SHALL NOT», «СЛЕДУЕТ — SHOULD», «НЕ СЛЕДУЕТ — SHOULD NOT», «РЕКОМЕНДУЕТСЯ — RECOMMENDED», «НЕ РЕКОМЕНДУЕТСЯ — NOT RECOMMENDED», «ВОЗМОЖЕН — MAY» и «ДОПОЛНИТЕЛЬНО — OPTIONAL» в этом документе интерпретироваться как описано в [RFC2119 #] [RFC8174 #].

Критерии соответствия и соображения, касающиеся обработки ошибок, определены в разделе 2.5 [RFC7230 #].

1.2. Синтаксическая нотация

В этой спецификации используется нотация расширенной формы Бэкуса-Наура (ABNF) в [RFC5234 #] с расширением списка, определенным в разделе 7 [RFC7230 #], который позволяет компактно определять списки, разделенные запятыми, используя оператор «#» (аналогично как оператор ‘*’ указывает на повторение). Приложение B описывает правила, импортированные из других документов. Приложение C показывает собранную грамматику со всеми операторами списка, расширенными до стандартной записи ABNF.

2. Валидаторы

В этой спецификации определяются две формы метаданных, которые обычно используются для наблюдения за состоянием ресурса и проверки предварительных условий: даты изменения (раздел 2.2) и теги непрозрачных объектов (раздел 2.3). Дополнительные метаданные, которые отражают состояние ресурса, были определены различными расширениями HTTP, такими как «Web Distributed Authoring and Versioning» (WebDAV, [RFC4918 #]), которые выходят за рамки данной спецификации. Значение метаданных ресурса называется «validator» (валидатором), когда оно используется в предварительном условии.

2.1. Слабые против сильных (weak validator versus strong validator)

Валидаторы бывают двух видов: сильные или слабые. Слабые валидаторы легко генерировать, но они гораздо менее полезны для сравнения. Сильные валидаторы идеальны для сравнений, но их может быть очень сложно (а иногда и невозможно) эффективно сгенерировать. Вместо того чтобы навязывать, что все формы ресурсов придерживаются одной и той же силы валидатора, HTTP предоставляет тип используемого валидатора и накладывает ограничения на использование слабых валидаторов в качестве предварительных условий.

«Сильный валидатор» (strong validator)  — это метаданные представления, которые изменяют значение всякий раз, когда происходит изменение данных представления, которые можно было бы наблюдать в теле полезной нагрузки ответа 200 (ОК) на GET.

Сильный валидатор может измениться по причинам, отличным от изменения данных представления, например, когда изменяется семантически значимая часть метаданных представления (например, Content-Type), но в интересах исходного сервера только измените значение, когда необходимо аннулировать хранимые ответы, хранящиеся в удаленных кэшах и средствах разработки.

Записи кэша могут сохраняться в течение сколь угодно длительных периодов, независимо от времени истечения. Таким образом, кэш может попытаться проверить запись, используя валидатор, полученный в далеком прошлом. Сильный валидатор уникален во всех версиях всех представлений, связанных с конкретным ресурсом с течением времени. Тем не менее, нет никакой уникальности в представлениях разных ресурсов (т. е. Один и тот же строгий валидатор может использоваться для представлений нескольких ресурсов одновременно и не означает, что эти представления эквивалентны).

Существует множество сильных валидаторов, используемых на практике. Лучшие из них основаны на строгом контроле версий, при котором каждое изменение представления всегда приводит к тому, что уникальное имя узла и идентификатор редакции назначаются до того, как представление становится доступным для GET. Устойчивая к столкновениям хеш-функция, применяемая к данным представления, также достаточна, если данные доступны до отправки полей заголовка ответа, и дайджест не нужно пересчитывать каждый раз, когда получен запрос проверки. Однако если у ресурса есть разные представления, которые отличаются только метаданными, что может произойти при согласовании контента по типам мультимедиа, которые совместно используют один и тот же формат данных, то исходный сервер должен включить в валидатор дополнительную информацию, чтобы различать эти представления.

Напротив, «слабый валидатор» (weak validator) — это метаданные представления, которые могут не изменяться при каждом изменении данных представления. Эта слабость может быть связана с ограничениями в способе вычисления значения, такими как разрешение часов, неспособность обеспечить уникальность для всех возможных представлений ресурса или желание владельца ресурса сгруппировать представления по некоторому само-определенному набору эквивалентности. а не уникальные последовательности данных. Исходный сервер ДОЛЖЕН изменить слабый тег объекта всякий раз, когда он считает, что предыдущие представления являются неприемлемыми в качестве замены текущего представления. Другими словами, слабый объектный тег должен изменяться всякий раз, когда исходный сервер хочет, чтобы кэши делали недействительными старые ответы.

Например, представление метеорологического отчета, который меняется в содержании каждую секунду, на основе динамических измерений, может быть сгруппировано в наборы эквивалентных представлений (с точки зрения исходного сервера) с одним и тем же слабым валидатором, чтобы позволить кэшированным представлениям быть действительными в течение разумного периода времени (возможно, динамически настраивается в зависимости от нагрузки на сервер или качества погоды). Аналогично, время изменения представления, если оно определено с разрешением всего в одну секунду, может быть слабым средством проверки, если возможно, чтобы представление было изменено дважды в течение одной секунды и извлечено между этими изменениями.

Аналогично, валидатор является слабым, если он совместно используется двумя или более представлениями данного ресурса одновременно, если только эти представления не имеют идентичных данных представления. Например, если исходный сервер отправляет тот же валидатор для представления с примененным кодированием контента gzip, как и для представления без кодирования контента, тогда этот валидатор слабый. Однако два одновременных представления могут совместно использовать один и тот же строгий валидатор, если они отличаются только метаданными представления, например, когда два разных типа мультимедиа доступны для одних и тех же данных представления.

Сильные валидаторы можно использовать для всех условных запросов, включая проверку кэша, частичные диапазоны содержимого и предотвращение «потерянных обновлений» (lost update). Слабые валидаторы используются только тогда, когда клиенту не требуется точное равенство с ранее полученными данными представления, например, при проверке записи в кэше или ограничении веб-обхода последними изменениями.

2.2. Заголовок Last-Modified (Последнее изменение)

Поле заголовка «Last-Modified» в ответе содержит временную метку, указывающую дату и время, когда сервер-источник считает, что выбранное представление было последний раз изменено, как было определено в конце обработки запроса.

Last-Modified = HTTP-date

Примером его использования является

Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT

2.2.1. Генерация

Исходному серверу СЛЕДУЕТ отправлять Last-Modified для любого выбранного представления, для которого можно разумно и последовательно определить дату последней модификации, поскольку его использование в условных запросах и оценке свежести кэша ([RFC7234 #]) приводит к значительному сокращению трафика HTTP на Интернет и может стать существенным фактором повышения масштабируемости и надежности услуг.

Представление обычно является суммой многих частей за интерфейсом ресурса. Время последнего изменения, как правило, будет последним временем, когда любая из этих частей была изменена. То, как это значение определяется для любого данного ресурса, является подробностью реализации, выходящей за рамки данной спецификации. Для HTTP важно то, как получатели поля заголовка Last-Modified могут использовать его значение для создания условных запросов и проверки достоверности локально кэшированных ответов.

Исходный сервер ДОЛЖЕН получить значение Last-Modified представления как можно ближе ко времени, когда он генерирует значение поля Date для своего ответа. Это позволяет получателю сделать точную оценку времени изменения представления, особенно если представление изменяется вблизи времени генерирования ответа.

Исходный сервер с часами НЕ ДОЛЖЕН отправлять дату последнего изменения, которая является более поздней, чем время создания сообщения сервером (Date). Если время последней модификации получено из специфических для реализации метаданных, которые оцениваются до некоторого времени в будущем, согласно часам сервера источника, то сервер происхождения ДОЛЖЕН заменить это значение датой происхождения сообщения. Это предотвращает неблагоприятное влияние будущей даты модификации на проверку кэша.

Исходный сервер без часов НЕ ДОЛЖЕН присваивать ответу значения Last-Modified, если только эти значения не были связаны с ресурсом какой-либо другой системой или пользователем с надежными часами.

2.2.2. Сравнение

Время последнего изменения, когда оно используется в качестве валидатора в запросе, неявно слабое, если только невозможно определить его силу, используя следующие правила:

  • Валидатор сравнивается исходным сервером с фактическим текущим валидатором для представления и,
  • Этот исходный сервер достоверно знает, что связанное представление не менялось дважды в течение секунды, охватываемой представленным средством проверки.

или же

  • Валидатор собирается использоваться клиентом в поле заголовка If-Modified-Since, If-Unmodified-Since или If-Range, потому что клиент имеет запись в кэше для ассоциированного представления, и
  • Эта запись в кэше содержит значение Date, которое указывает время, когда исходный сервер отправил исходный ответ, и
  • Представленное время последнего изменения не менее чем за 60 секунд до значения Date.

или же

  • Валидатор сравнивается промежуточным кэшем с валидатором, хранящимся в его записи кэша для представления, и
  • Эта запись в кэше содержит значение Date, которое указывает время, когда исходный сервер отправил исходный ответ, и
  • Представленное время последнего изменения не менее чем за 60 секунд до значения Date.

Этот метод основан на том факте, что если исходный сервер отправил два разных ответа в течение одной и той же секунды, но оба имели одинаковое время последнего изменения, то хотя бы один из этих ответов будет иметь значение Date, равное его Last-Modified времени. Произвольный 60-секундный предел защищает от возможности того, что значения Date и Last-Modified генерируются из разных часов или в несколько разное время при подготовке ответа. Реализация МОЖЕТ использовать значение больше 60 секунд, если считается, что 60 секунд слишком мало.

2.3. Заголовок ETag (Метка объекта — Entity tag)

Поле заголовка «ETag» в ответе предоставляет текущий тег объекта для выбранного представления, как это определено в конце обработки запроса. Тэг объекта является непрозрачным средством проверки правильности для различения нескольких представлений одного и того же ресурса, независимо от того, являются ли эти множественные представления следствием изменений состояния ресурса с течением времени, согласования содержимого, приводящего к тому, что несколько представлений являются действительными одновременно или оба. Entity-tag (Метка объекта) состоит из непрозрачной строки в кавычках, возможно с префиксом индикатора слабости.

ETag = entity-tag


entity-tag = [ weak ] opaque-tag
weak = %x57.2F ; "W/", case-sensitive
opaque-tag = DQUOTE *etagc DQUOTE
etagc = %x21 / %x23-7E / obs-text ; VCHAR кроме двойных кавычек, плюс obs-text

Примечание. Ранее непрозрачный тег (opaque-tag) был определен как строка в кавычках ([RFC2616 #], раздел 3.11); таким образом, некоторые получатели могут выполнять обратный слэш без экранирования. Поэтому серверам следует избегать символов обратной косой черты в тегах объектов.

Тэг объекта может быть более надежным для проверки, чем дата модификации, в ситуациях, когда неудобно хранить даты модификации, когда одно-секундное разрешение значений даты HTTP недостаточно, или когда даты модификации не всегда поддерживаются.

Примеры:

ETag: "xyzzy"
ETag: W/"xyzzy"
ETag: ""

Entity-tag (Метка объекта) может быть как слабым, так и сильным валидатором, с сильным по умолчанию. Если сервер происхождения предоставляет тег объекта для представления, и генерация этого тега объекта не удовлетворяет всем характеристикам строгого валидатора (раздел 2.1), то сервер происхождения ДОЛЖЕН пометить тег объекта как слабый с помощью префикса его непрозрачное значение с «W/» (чувствительно к регистру).

2.3.1. Генерация

Принцип, лежащий в основе тегов объекта, заключается в том, что только автор службы знает реализацию ресурса достаточно хорошо, чтобы выбрать наиболее точный и эффективный механизм проверки для этого ресурса, и что любой такой механизм может быть сопоставлен с простой последовательностью октетов для простого сравнения. Поскольку значение непрозрачно, клиенту не нужно знать, как создается каждый тег объекта.

Например, ресурс, который имеет привязку к реализации для всех изменений, может использовать внутренний номер редакции, возможно, в сочетании с идентификатором отклонения для согласования контента, чтобы точно различать представления. Другие реализации могут использовать устойчивый к столкновениям хэш содержимого представления, комбинацию различных атрибутов файла или метку времени модификации, которая имеет разрешение менее секунды.

Сервер происхождения ДОЛЖЕН послать ETag для любого выбранного представления, для которого можно разумно и последовательно определить обнаружение изменений, поскольку использование тега объекта в условных запросах и оценке свежести кэша ([RFC7234 #]) может привести к значительному сокращению сети HTTP-трафика и может стать существенным фактором повышения масштабируемости и надежности услуг.

2.3.2. Сравнение

Существует две функции сравнения тегов объектов, в зависимости от того, позволяет ли контекст сравнения использовать слабые валидаторы:

  • Сильное сравнение (Strong Comparison): два тега объекта эквивалентны, если оба не являются слабыми, а их непрозрачные теги совпадают символ за символом.
  • Слабое сравнение (Weak Comparison): два тега объекта эквивалентны, если их непрозрачные теги совпадают посимвольно, независимо от того, помечен один или оба тега как «слабый» (weak).

В приведенном ниже примере показаны результаты для набора пар объект-тег, а также результаты функции слабого и сильного сравнения:

ETag 1 ETag 2 Strong Comparison Weak Comparison
W/»1″ W/»1″ no match match
W/»1″ W/»2″ no match no match
W/»1″ «1» no match match
«1» «1» match match

Таблица

2.3.3. Пример: Entity-Tags (теги сущностей), изменяющиеся на ресурсах с согласованным содержимым

Рассмотрим ресурс, который подлежит согласованию контента (Раздел 3.4 [RFC7231 #]), и где представления, отправленные в ответ на запрос GET, варьируются в зависимости от поля заголовка запроса Accept-Encoding (Раздел 5.3.4 [RFC7231 #]):

>> Request:

GET /index HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip

В этом случае ответ может использовать или не использовать кодировку содержимого gzip. Если это не так, ответ может выглядеть так:

>> Response:

HTTP/1.1 200 OK
Date: Fri, 26 Mar 2010 00:05:00 GMT
ETag: "123-a"
Content-Length: 70
Vary: Accept-Encoding
Content-Type: text/plain

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

Альтернативное представление, которое использует кодирование содержимого gzip:

>> Response:

HTTP/1.1 200 OK
Date: Fri, 26 Mar 2010 00:05:00 GMT
ETag: "123-b"
Content-Length: 43
Vary: Accept-Encoding
Content-Type: text/plain
Content-Encoding: gzip

...binary data...

Примечание. Кодирование содержимого является свойством данных представления, поэтому сильный тег объекта для представления с кодированием содержимого должен отличаться от тега объекта незакодированного представления, чтобы предотвратить потенциальные конфликты во время обновлений кэша и запросов диапазона. Напротив, кодировки передачи (раздел 4 [RFC7230 #]) применяются только во время передачи сообщений и не приводят к отдельным тегам объекта.

2.4. Когда использовать Entity-Tags (теги сущностей) и даты Last-Modified (последнего изменения)

В 200 (ОК) ответах на GET или HEAD сервер происхождения:

  • ДОЛЖЕН послать валидатор тэга объекта, если его невозможно сгенерировать.
  • МОЖЕТ отправить слабый тег объекта вместо сильного тега объекта, если соображения производительности поддерживают использование слабых тегов объекта или если невозможно отправить сильный тег объекта.
  • ДОЛЖЕН отправить значение Last-Modified, если это возможно.

Другими словами, предпочтительным поведением для исходного сервера является отправка как сильного тега объекта, так и значения Last-Modified в успешных ответах на запрос поиска.

Клиент:

  • ДОЛЖЕН послать этот тег объекта в любом запросе проверки кэша (используя If-Match или If-None-Match), если тег объекта был предоставлен сервером происхождения.
  • СЛЕДУЕТ отправлять значение Last-Modified в запросах проверки кэша не поддиапазона (используя If-Modified-Since), если исходный сервер предоставил только значение Last-Modified.
  • МОЖЕТ отправлять значение Last-Modified в запросах проверки кэша поддиапазона (используя If-Unmodified-Since), если сервер происхождения HTTP/1.0 предоставил только значение Last-Modified. Пользовательский агент ДОЛЖЕН предоставить способ отключить это в случае затруднений.
  • СЛЕДУЕТ отправлять оба средства проверки в запросах проверки кэша, если исходный сервер предоставил оба тега объекта и значение Last-Modified. Это позволяет кешам HTTP/1.0 и HTTP/1.1 отвечать соответствующим образом.

3. Поля заголовка предварительного условия

Этот раздел определяет синтаксис и семантику полей заголовка HTTP/1.1 для применения предварительных условий к запросам. Раздел 5 определяет, когда применяются предварительные условия. Раздел 6 определяет порядок оценки, когда присутствует более чем одно предварительное условие.

3.1. If-Match

Поле заголовка «If-Match» делает метод запроса условным на сервере источника-получателя, имеющего по крайней мере одно текущее представление целевого ресурса, когда значение поля равно звёздочка «*», или имеющем текущее представление целевого ресурса, которое имеет тег объекта, соответствующий элементу списка тегов объекта, предоставленного в значении поля.

Сервер происхождения ДОЛЖЕН использовать функцию строгого сравнения при сравнении тегов объекта для If-Match (раздел 2.3.2), поскольку клиент намерен выполнить это предварительное условие, чтобы предотвратить применение метода, если в данных представления произошли какие-либо изменения.

If-Match = "*" / 1#entity-tag

Примеры:

If-Match: "xyzzy"
If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-Match: *

If-Match чаще всего используется с методами изменения состояния (например, POST, PUT, DELETE) для предотвращения случайных перезаписей, когда несколько пользовательских агентов могут работать параллельно на одном и том же ресурсе (т. е. Для предотвращения проблемы «потерянного обновления»). Он также может использоваться с безопасными методами для отмены запроса, если выбранное представление не совпадает с уже сохраненным (или частично сохраненным) из предыдущего запроса.

Исходный сервер, который получает поле заголовка If-Match, ДОЛЖЕН оценить условие до выполнения метода (раздел 5). Если значение поля равно звёздочке «*», условие ложно, если исходный сервер не имеет текущего представления для целевого ресурса. Если значение поля представляет собой список тегов объекта, условие ложно, если ни один из перечисленных тегов не соответствует тегу объекта выбранного представления.

Исходный сервер НЕ ДОЛЖЕН выполнять запрошенный метод, если полученное условие If-Match оценивается как ложное; вместо этого сервер происхождения ДОЛЖЕН ответить, либо а) кодом состояния 412 (Не выполнено предварительное условие), либо б) одним из кодов состояния 2xx (Успешно), если сервер источника подтвердил, что запрашивается изменение состояния, а окончательное состояние уже отражено в текущем состоянии целевого ресурса (т. е. изменение, запрошенное пользовательским агентом, уже успешно выполнено, но пользовательский агент может не знать об этом, возможно, из-за того, что предыдущий ответ был потерян или совместимое изменение было сделано каким-то другим пользовательским агентом). В последнем случае сервер происхождения НЕ ДОЛЖЕН отправлять поле заголовка валидатора в ответе, если только он не может проверить, что запрос является дубликатом непосредственно предшествующего изменения, внесенного тем же пользовательским агентом.

Кэши и посредники могут игнорировать поле заголовка If-Match, поскольку оно неприменимо к сохраненному ответу.

3.2. If-None-Match

Поле заголовка «If-None-Match» делает метод запроса условным для кэша получателя или исходного сервера, либо не имеющего какого-либо текущего представления целевого ресурса, когда значение поля равно звёздочке «*», либо имеющего выбранное представление с тег сущности, который не соответствует ни одному из перечисленных в значении поля.

Получатель ДОЛЖЕН использовать функцию слабого сравнения при сравнении тегов объекта для If-None-Match (раздел 2.3.2), поскольку слабые теги объекта могут использоваться для проверки кэша, даже если в данные представления были внесены изменения.

If-None-Match = "*" / 1#entity-tag

Примеры:

If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *

If-None-Match в основном используется в условных запросах GET, чтобы обеспечить эффективное обновление кэшированной информации с минимальным объемом транзакций. Когда клиент желает обновить один или несколько сохраненных ответов, которые имеют теги объекта, клиент должен генерировать поле заголовка If-None-Match, содержащее список этих тегов объекта, при выполнении запроса GET; это позволяет серверам получателей отправлять ответ 304 (не измененный), чтобы указать, когда один из этих сохраненных ответов соответствует выбранному представлению.

If-None-Match также можно использовать со значением звёздочки «*», чтобы предотвратить непреднамеренное изменение небезопасным методом запроса (например, PUT) существующего представления целевого ресурса, когда клиент полагает, что ресурс не имеет текущего представления (Раздел 4.2.1 [RFC7231 #]). Это вариант проблемы «потерянных обновлений», которая может возникнуть, если несколько клиентов пытаются создать начальное представление для целевого ресурса.

Исходный сервер, который получает поле заголовка If-None-Match, ДОЛЖЕН оценить условие до выполнения метода (раздел 5). Если значение поля равно звёздочке «*», условие ложно, если исходный сервер имеет текущее представление для целевого ресурса. Если значение поля представляет собой список тегов объекта, условие ложно, если один из перечисленных тегов соответствует тегу объекта выбранного представления.

Исходный сервер НЕ ДОЛЖЕН выполнять запрошенный метод, если условие оценивается как ложное; вместо этого сервер происхождения ДОЛЖЕН ответить либо a) кодом состояния 304 (не изменен), если метод запроса — GET или HEAD, либо b) кодом состояния 412 (не выполнено предварительное условие) для всех других методов запроса.

Требования к обработке кэша полученного поля заголовка If-None-Match определены в Разделе 4.3.2 [RFC7234 #].

3.3. If-Modified-Since

Поле заголовка «If-Modified-Since» делает метод запроса GET или HEAD условным, поскольку дата модификации выбранного представления является более поздней, чем дата, указанная в значении поля. Передача данных выбранного представления исключается, если эти данные не изменились.

If-Modified-Since = HTTP-date

Пример поля:

If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

Получатель ДОЛЖЕН игнорировать If-Modified-Since, если запрос содержит поле заголовка If-None-Match; условие в If-None-Match считается более точной заменой условия в If-Modified-Since, и они объединяются только для взаимодействия со старшими посредниками, которые могут не реализовать If-None-Match.

Получатель ДОЛЖЕН игнорировать поле заголовка If-Modified-Since, если полученное значение поля не является действительной HTTP-датой или если метод запроса не является ни GET, ни HEAD.

Получатель ДОЛЖЕН интерпретировать временную метку значения поля If-Modified-Since в терминах часов исходного сервера.

If-Modified-Since обычно используется для двух разных целей: 1) для обеспечения эффективного обновления кэшированного представления, которое не имеет тега объекта, и 2) для ограничения области веб-поиска для ресурсов, которые недавно изменились.

При использовании для обновлений кэша кэш будет обычно использовать значение поля Last-Modified кэшированного сообщения для генерации значения поля If-Modified-Since. Такое поведение наиболее совместимо для случаев, когда часы плохо синхронизированы или когда сервер выбрал только точное совпадение с отметками времени (из-за проблемы с датами последнего изменения, которые, по-видимому, возвращаются «назад во времени» (back in time), когда часы исходного сервера исправлены или представление восстанавливается из архивной резервной копии). Однако кэши иногда генерируют значение поля на основе других данных, таких как поле заголовка Date кэшированного сообщения или локальное время, в которое сообщение было получено, особенно если кэшированное сообщение не содержит поле Last-Modified.

При использовании для ограничения области поиска недавним временным окном, пользовательский агент генерирует значение поля If-Modified-Since на основе либо своих собственных локальных часов, либо поля заголовка Date, полученного от сервера в предыдущем ответе. Исходные серверы, которые выбирают точное совпадение меток времени на основе поля Last-Modified выбранного представления, не смогут помочь агенту пользователя ограничить передачу данных только теми, которые были изменены в течение указанного окна.

Исходный сервер, который получает поле заголовка If-Modified-Since, ДОЛЖЕН оценить условие перед выполнением метода (раздел 5). Исходный сервер НЕ ДОЛЖЕН выполнять запрошенный метод, если дата последнего изменения выбранного представления раньше или равна дате, указанной в значении поля; вместо этого исходный сервер ДОЛЖЕН генерировать ответ 304 (не модифицированный), включая только те метаданные, которые полезны для идентификации или обновления ранее кэшированного ответа.

Требования к обработке кэша полученного поля заголовка If-Modified-Since определены в Разделе 4.3.2 [RFC7234 #].

3.4. If-Unmodified-Since

Поле заголовка «If-Unmodified-Since» делает метод запроса зависящим от даты последнего изменения выбранного представления, предшествующей или равной дате, указанной в значении поля. Это поле выполняет ту же цель, что и If-Match для случаев, когда пользовательский агент не имеет тега сущности для представления.

If-Unmodified-Since = HTTP-date

Пример поля:

If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT

Получатель ДОЛЖЕН игнорировать If-Unmodified-Since, если запрос содержит поле заголовка If-Match; условие в If-Match считается более точной заменой условия в If-Unmodified-Since, и они объединяются только для взаимодействия с более старыми посредниками, которые могут не реализовать If-Match.

Получатель ДОЛЖЕН игнорировать поле заголовка If-Unmodified-Since, если полученное значение поля не является действительной HTTP-датой.

Получатель ДОЛЖЕН интерпретировать временную метку значения поля If-Unmodified-Since в терминах часов исходного сервера.

If-Unmodified-Since чаще всего используется с методами изменения состояния (например, POST, PUT, DELETE) для предотвращения случайных перезаписей, когда несколько пользовательских агентов могут работать параллельно с ресурсом, который не предоставляет теги объекта с его представлениями (т.е., чтобы предотвратить проблему «потерянного обновления»). Он также может использоваться с безопасными методами для отмены запроса, если выбранное представление не совпадает с уже сохраненным (или частично сохраненным) из предыдущего запроса.

Исходный сервер, который получает поле заголовка If-Unmodified-Since, ДОЛЖЕН оценить условие до выполнения метода (раздел 5). Исходный сервер НЕ ДОЛЖЕН выполнять запрошенный метод, если дата последнего изменения выбранного представления является более поздней, чем дата, указанная в значении поля; вместо этого сервер происхождения ДОЛЖЕН ответить либо: а) кодом состояния 412 (Не выполнено предварительное условие), либо б) одним из кодов состояния 2xx (Успешно), если сервер происхождения подтвердил, что запрашивается изменение состояния, и окончательное состояние уже отражено. в текущем состоянии целевого ресурса (т. е. изменение, запрошенное пользовательским агентом, уже успешно выполнено, но пользовательский агент может не знать об этом, потому что предыдущее ответное сообщение было потеряно или совместимое изменение было сделано другим пользовательским агентом). В последнем случае сервер происхождения НЕ ДОЛЖЕН отправлять поле заголовка валидатора в ответе, если только он не может проверить, что запрос является дубликатом непосредственно предшествующего изменения, внесенного тем же пользовательским агентом.

Поле заголовка If-Unmodified-Since может игнорироваться кешами и посредниками, поскольку оно не применимо к сохраненному ответу.

3.5. If-Range

Поле заголовка «If-Range» предоставляет специальный механизм условного запроса, который аналогичен полям заголовка If-Match и If-Unmodified-Since, но в котором указывается получателю игнорировать поле заголовка Range, если валидатор не совпадает, в результате чего в передаче нового выбранного представления вместо ответа 412 (Precondition Failed). If-Range определен в разделе 3.2 [RFC7233 #].

4. Определения кода состояния

4.1. Код 304 — Не модифицировано

Код состояния 304 (не изменен) указывает на то, что был получен условный запрос GET или HEAD, что привело бы к ответу 200 (ОК), если бы не тот факт, что условие оценивается как ложное. Другими словами, серверу нет необходимости передавать представление целевого ресурса, поскольку запрос указывает, что клиент, который сделал запрос условным, уже имеет действительное представление; поэтому сервер перенаправляет клиента использовать это сохраненное представление, как если бы оно было полезной нагрузкой ответа 200 (ОК).

Сервер, генерирующий ответ 304, ДОЛЖЕН сгенерировать любое из следующих полей заголовка, которые были бы отправлены в ответе 200 (ОК) на тот же запрос: Cache-Control, Content-Location, Date, ETag, Expires и Vary.

Поскольку цель ответа 304 состоит в том, чтобы минимизировать передачу информации, когда у получателя уже есть одно или несколько кэшированных представлений, отправителю НЕ СЛЕДУЕТ генерировать метаданные представления, отличные от перечисленных выше полей, если только эти метаданные не существуют для направления обновлений кэша (например, Последнее изменение может быть полезно, если в ответе нет поля ETag).

Требования к кешу, который получает ответ 304, определены в Разделе 4.3.4 [RFC7234 #]. Если условный запрос был инициирован исходящим клиентом, таким как пользовательский агент со своим собственным кешем, отправляющим условный GET на общий прокси-сервер, то прокси-сервер ДОЛЖЕН переслать ответ 304 этому клиенту.

Ответ 304 не может содержать тело сообщения; он всегда заканчивается первой пустой строкой после полей заголовка.

4.2. Код 412 — Не выполнено предварительное условие

Код состояния 412 (Ошибка предварительного условия) указывает, что одно или несколько условий, заданных в полях заголовка запроса, оцениваются как ложные при тестировании на сервере. Этот код ответа позволяет клиенту помещать предварительные условия в текущее состояние ресурса (его текущие представления и метаданные) и, таким образом, предотвращает применение метода запроса, если целевой ресурс находится в неожиданном состоянии.

5. Оценка

За исключением случаев, исключенных ниже, кэш-память получателя или сервер происхождения ДОЛЖНЫ оценивать принятые предварительные условия запроса после того, как он успешно выполнил свои обычные проверки запроса и непосредственно перед тем, как он выполнит действие, связанное с методом запроса. Сервер ДОЛЖЕН игнорировать все полученные предварительные условия, если его ответ на один и тот же запрос без этих условий был бы кодом состояния, отличным от 2xx (Успешно) или 412 (Условие не выполнено). Другими словами, перенаправления и сбои имеют приоритет над оценкой предварительных условий в условных запросах.

Сервер, который не является исходным сервером для целевого ресурса и не может выступать в качестве кэша для запросов к целевому ресурсу, НЕ ДОЛЖЕН оценивать поля заголовка условного запроса, определенные в этой спецификации, и он ДОЛЖЕН пересылать их, если запрос перенаправлен, поскольку генерирующий клиент предполагает, что он будет оценен сервером, который может предоставить текущее представление. Аналогичным образом, сервер ДОЛЖЕН игнорировать поля заголовка условного запроса, определенные в этой спецификации, при получении с помощью метода запроса, который не включает выбор или изменение выбранного представления, такого как CONNECT, OPTIONS или TRACE.

Поля заголовка условного запроса, определяемые расширениями HTTP, могут накладывать условия на всех получателей, на состояние целевого ресурса в целом или на группу ресурсов. Например, поле заголовка «If» в WebDAV может сделать запрос условным для различных аспектов нескольких ресурсов, таких как блокировки, если получатель понимает и реализует это поле ([RFC4918 #], раздел 10.4).

Хотя поля заголовка условного запроса определены как пригодные для использования с методом HEAD (чтобы семантика HEAD соответствовала семантике GET), нет смысла отправлять условный HEAD, поскольку размер успешного ответа примерно равен размеру 304 (не изменен) и более полезный, чем ответ 412 (Precondition Failed).

6. Приоритет

Когда в запросе присутствует более одного поля заголовка условного запроса, порядок, в котором оцениваются поля, становится важным. На практике поля, определенные в этом документе, последовательно реализуются в едином логическом порядке, поскольку предварительные условия «потерянного обновления» предъявляют более строгие требования, чем проверка кеша, проверенный кеш более эффективен, чем частичный ответ, и предполагается, что теги сущностей должны быть более точным, чем валидаторы даты.

Кэш получателя или сервер источника ДОЛЖЕН оценить предварительные условия запроса, определенные в этой спецификации, в следующем порядке:

  1. Когда получатель является исходным сервером и присутствует If-Match, оцените предварительное условие If-Match:
  • если верно, перейдите к шагу 3
  • если неверно, ответьте 412 (Precondition Failed), если только вы не можете определить, что запрос на изменение состояния уже успешно выполнен (см. раздел 3.1)
  1. Если получателем является исходный сервер, если If-Match отсутствует, а If-Unmodified-Since присутствует, оценивают предварительное условие If-Unmodified-Since:
  • если верно, перейдите к шагу 3
  • если неверно, ответьте 412 (Precondition Failed), если только вы не можете определить, что запрос на изменение состояния уже успешно выполнен (см. раздел 3.4)
  1. Если присутствует If-None-Match, оцените предварительное условие If-None-Match:
  • если верно, перейдите к шагу 5
  • если неверно для GET/HEAD, ответьте 304 (не изменено)
  • если неверно для других методов, ответьте 412 (Precondition Failed)
  1. Если используется метод GET или HEAD, если If-None-Match отсутствует, а If-Modified-Since присутствует, оценивают предварительное условие If-Modified-Since:
  • если верно, перейдите к шагу 5
  • если неверно, ответьте 304 (Не изменено)
  1. Когда метод GET и присутствуют и Range, и If-Range, оцените предварительное условие If-Range:
  • если валидатор совпадает и спецификация диапазона применима к выбранному представлению, ответьте 206 (Частичное содержимое) [RFC7233 #]
  1. В противном случае,
  • все условия выполнены, поэтому выполните запрошенное действие и ответьте в соответствии с его успехом или неудачей.

Любое расширение к HTTP/1.1, которое определяет дополнительные поля заголовка условного запроса, должно определять его собственные ожидания относительно порядка оценки таких полей относительно тех, которые определены в этом документе, и других условий, которые могут быть найдены на практике.

7. Соображения IANA

7.1. Регистрация кода статуса

«Реестр кодов состояния протокола передачи гипертекста (HTTP)», расположенный по адресу <http://www.iana.org/assignments/http-status-codes>, обновлен следующими регистрациями:

Код состояния Описание Определено в  …
304 Not Modified (Не модифицировано) Раздел 4.1
412 Precondition Failed (Предварительное условие не выполнено) Раздел 4.2

Таблица

7.2. Регистрация поля заголовка

Поля заголовка HTTP регистрируются в реестре «Заголовки сообщений», который ведется по адресу <http://www.iana.org/assignments/message-headers/>.

В этом документе определены следующие поля заголовка HTTP, поэтому соответствующие записи реестра были обновлены в соответствии с постоянной регистрацией ниже (см. [BCP90]):

Имя поля заголовка Протокол Статус Определено в  …
ETag http standard Раздел 2.3
If-Match http standard Раздел 3.1
If-Modified-Since http standard Раздел 3.3
If-None-Match http standard Раздел 3.2
If-Unmodified-Since http standard Раздел 3.4
Last-Modified http standard Раздел 2.2

Таблица

Контроллер изменений: «IETF (iesg@ietf.org) — Целевая рабочая группа по Интернету».

8. Вопросы безопасности

Этот раздел предназначен для информирования разработчиков, поставщиков информации и пользователей об известных проблемах безопасности, связанных с механизмами условных запросов HTTP. Более общие соображения безопасности рассматриваются в HTTP «Синтаксис и маршрутизация сообщений» [RFC7230 #] и «Семантика и контент» [RFC7231 #].

Валидаторы, определенные в этой спецификации, не предназначены для обеспечения достоверности представления, защиты от злонамеренных изменений или обнаружения атак «человек посередине» (man-in-the-middle). В лучшем случае они обеспечивают более эффективные обновления кэша и оптимистичные параллельные записи, когда все участники ведут себя хорошо. В худшем случае условия не будут выполнены, и клиент получит ответ, который не более опасен, чем обмен HTTP без условных запросов.

С тэгом объекта можно злоупотреблять способами, которые создают риски для конфиденциальности. Например, сайт может намеренно создать семантически недопустимый тег объекта, который является уникальным для пользователя или пользовательского агента, отправить его в кэшируемом ответе с длительным временем обновления и затем прочитать этот тег объекта в последующих условных запросах в качестве средства повторной идентификации этого пользователя или пользовательского агента. Такой идентификационный тег станет постоянным идентификатором до тех пор, пока пользовательский агент сохранит исходную запись в кэше. Пользовательские агенты, которые кэшируют представления, должны гарантировать, что кэш очищается или заменяется всякий раз, когда пользователь выполняет действия по поддержанию конфиденциальности, такие как очистка сохраненных файлов cookie или переход в режим частного просмотра.

9. Благодарности

См. Раздел 10 [RFC7230 #].

10. Ссылки

10.1. Нормативные ссылки

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, March 1997.

[RFC5234] Crocker, D., Ed. and P. Overell, «Augmented BNF for Syntax Specifications: ABNF», STD 68, RFC 5234, January 2008.

[RFC7230] Fielding, R., Ed. and J. Reschke, Ed., «Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing», RFC 7230, June 2014.

[RFC7231] Fielding, R., Ed. and J. Reschke, Ed., «Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content», RFC 7231, June 2014.

[RFC7233] Fielding, R., Ed., Lafon, Y., Ed., and J. Reschke, Ed., «Hypertext Transfer Protocol (HTTP/1.1): Range Requests», RFC 7233, June 2014.

[RFC7234] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., «Hypertext Transfer Protocol (HTTP/1.1): Caching», RFC 7234, June 2014.

10.2. Информационные ссылки

[BCP90] Klyne, G., Nottingham, M., and J. Mogul, «Registration Procedures for Message Header Fields», BCP 90, RFC 3864, September 2004.

[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, June 1999.

[RFC4918] Dusseault, L., Ed., «HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)», RFC 4918, June 2007.

Приложение A. Изменения по сравнению с RFC 2616

Определение слабости валидатора было расширено и уточнено. (Раздел 2.1)

Слабые теги сущностей теперь разрешены во всех запросах, кроме запросов диапазона. (Раздел 2.1 и раздел 3.2)

Поле заголовка ETag ABNF было изменено, чтобы не использовать строку в кавычках, что позволяет избежать проблем с выходом из строя. (Раздел 2.3)

ETag определен для предоставления тега объекта для выбранного представления, тем самым разъясняя, к чему он применяется в различных ситуациях (например, в ответе PUT). (Раздел 2.3)

Определен приоритет для оценки условных запросов. (Раздел 6)

Приложение B. Импортированный ABNF

Следующие основные правила включены посредством ссылки, как определено в Приложении B.1 [RFC5234 #]: ALPHA (буквы), CR (возврат каретки), CRLF (CR LF), CTL (элементы управления), DIGIT (десятичное 0-9) , DQUOTE (двойная кавычка), HEXDIG (шестнадцатеричный 0-9/A-F/a-f), LF (перевод строки), OCTET (любая 8-битная последовательность данных), SP (пробел) и VCHAR (любой видимый символ US-ASCII ).

Правила ниже определены в [RFC7230 #]:

OWS = <OWS, смотри [RFC7230 #], Раздел 3.2.3>
obs-text = <obs-text, смотри [RFC7230 #], Раздел 3.2.6>

Правила ниже определены в других частях:

HTTP-date = <HTTP-date, смотри [RFC7231 #], Раздел 7.1.1.1>

Приложение C. Собранный ABNF

В приведенной ниже ABNF правила списка расширены в соответствии с разделом 1.2 [RFC7230 #].

ETag = entity-tag

HTTP-date = <HTTP-date, смотри [RFC7231 #], Раздел 7.1.1.1>

If-Match = "*" / ( *( "," OWS ) entity-tag *( OWS "," [ OWS entity-tag ] ) )
If-Modified-Since = HTTP-date
If-None-Match = "*" / ( *( "," OWS ) entity-tag *( OWS "," [ OWS entity-tag ] ) )
If-Unmodified-Since = HTTP-date

Last-Modified = HTTP-date

OWS = <OWS, смотри [RFC7230 #], Раздел 3.2.3>

entity-tag = [ weak ] opaque-tag
etagc = "!" / %x23-7E ; ’#’-’~’ / obs-text

obs-text = <obs-text, смотри [RFC7230 #], Раздел 3.2.6>
opaque-tag = DQUOTE *etagc DQUOTE

weak = %x57.2F ; W/

Индекс

3

304 Not Modified (status code) 19

4

412 Precondition Failed (status code) 18

E

ETag header field 9

G

Grammar

entity-tag 9
ETag 9
etagc 9
If-Match 13
If-Modified-Since 15
If-None-Match 14
If-Unmodified-Since 17
Last-Modified 7
opaque-tag 9
weak 9

I

If-Match header field 13
If-Modified-Since header field 16
If-None-Match header field 14
If-Unmodified-Since header field 17

L

Last-Modified header field 7

M

metadata 5

S

selected representation 4

V

validator 5

strong 5
weak 5

Адреса авторов

Roy T. Fielding (editor)
Adobe Systems Incorporated
345 Park Ave
San Jose, CA 95110
USA
EMail: fielding@gbiv.com
URI: http://roy.gbiv.com/

Julian F. Reschke (editor)
greenbytes GmbH
Hafenweg 16
Muenster, NW 48155
Germany
EMail: julian.reschke@greenbytes.de
URI: http://greenbytes.de/tech/webdav/

Поделись записью