RFC 7540 | Протокол передачи гипертекста версии 2 (HTTP/2)

Аннотация

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

Эта спецификация является альтернативой синтаксису сообщений HTTP/1.1, но не устарела. Существующая семантика HTTP остается неизменной.
Скачать оригинальный документ на английском языке RFC 7540 PDF

Оглавление

1. Введение
2. Обзор протокола HTTP/2
2.1. Организация документов
2.2. Условные обозначения и терминология
3. Запуск HTTP/2
3.1. Идентификация версии HTTP/2
3.2. Запуск HTTP/2 для http-URI
3.2.1. Поле заголовка настроек HTTP2
3.3. Запуск HTTP/2 для URI «https»
3.4. Запуск HTTP/2 с предварительными знаниями
3.5. HTTP/2 Предисловие к подключению
4. HTTP-кадры
4.1. Формат кадра
4.2. Размер кадра
4.3. Сжатие заголовка и декомпрессия
5. Потоки и мультиплексирование
5.1. Состояния потока
5.1.1. Идентификаторы потока
5.1.2. Поток параллелизма
5.2. Управление потоком
5.2.1. Принципы управления потоком
5.2.2. Надлежащее использование контроля потока
5.3. Приоритет потока
5.3.1. Зависимости потока
5.3.2. Взвешивание зависимостей
5.3.3. Изменение приоритетов
5.3.4. Приоритет статуса управления
5.3.5. Приоритеты по умолчанию
5.4. Обработка ошибок
5.4.1. Обработка ошибок соединения
5.4.2. Обработка ошибок потока
5.4.3. Завершение соединения
5.5. Расширение HTTP/2
6. Определения кадров
6.1. DATA
6.2. HEADERS
6.3. PRIORITY
6.4. RST_STREAM
6.5. SETTINGS
6.5.1. Формат SETTINGS
6.5.2. Определенные параметры SETTINGS
6.5.3. Синхронизация настроек
6.6. PUSH_PROMISE
6.7. PING
6.8. GOAWAY
6.9. WINDOW_UPDATE
6.9.1. Окно Flow-Control
6.9.2. Начальный размер окна управления потоком
6.9.3. Уменьшение размера окна потока
6.10. CONTINUATION
7. Коды ошибок
8. Обмен сообщениями HTTP
8.1. Обмен HTTP-запросами / ответами
8.1.1. Обновление с HTTP/2
8.1.2. Поля заголовка HTTP
8.1.2.1. Поля псевдо-заголовка
8.1.2.2. Поля заголовка для конкретного соединения
8.1.2.3. Запросить псевдо-заголовочные поля
8.1.2.4. Поля псевдо-заголовка ответа
8.1.2.5. Сжатие поля заголовка файла cookie
8.1.2.6. Неверно сформированные запросы и ответы
8.1.3. Примеры
8.1.4. Запросить механизмы надежности в HTTP/2
8.2. Push-сервер
8.2.1. Push-запросы
8.2.2. Push-ответы
8.3. Метод CONNECT
9. Дополнительные требования HTTP / соображения
9.1. Управление подключением
9.1.1. Повторное использование подключения
9.1.2. Код состояния 421 (неверный запрос)
9.2. Использование функций TLS
9.2.1. TLS 1.2 Особенности
9.2.2. TLS 1.2 Cipher Suites
10. Вопросы безопасности
10.1. Полномочия сервера
10.2. Межпротокольные атаки
10.3. Посреднические инкапсуляционные атаки
10.4. Кешируемость отправленных ответов
10.5. Вопросы отказа в обслуживании
10.5.1. Ограничения на размер блока заголовка
10.5.2. CONNECT проблемы
10.6. Использование сжатия
10.7. Использование Padding
10.8. Вопросы конфиденциальности
11. Соображения IANA
11.1. Регистрация строк идентификации HTTP/2
11.2. Реестр кадров
11.3. Настройки реестра
11.4. Реестр кодов ошибок
11.5. HTTP2-настройки заголовка поля регистрации
11.6. PRI метод регистрации
11.7. Код состояния HTTP 421 (неверный запрос)
11.8. Жетон обновления h2c
12. Ссылки
12.1. Нормативные ссылки
12.2. Информационные ссылки
Приложение A. Черный список TLS 1.2 Cipher Suite
Благодарности
Адреса авторов

Статус этой заметки

Это документ по отслеживанию стандартов Интернета.

Этот документ является продуктом Инженерной рабочей группы по Интернету (IETF). Он представляет собой консенсус сообщества IETF. Он получил общественное обозрение и был одобрен для публикации Руководящей группой по Интернет-разработкам (IESG). Дополнительная информация о Интернет-стандартах доступна в Разделе 2 RFC 5741.

Информацию о текущем статусе этого документа, любых ошибках и способах предоставления обратной связи по нему можно получить по адресу http://www.rfc-editor.org/info/rfc7540.

Уведомление об авторских правах

Copyright (c) 2015 IETF Trust и лица, указанные в качестве авторов документа. Все права защищены.

На данный документ распространяется действие ПП 78 и Правовые положения IETF Trust, относящиеся к документам IETF (http://trustee.ietf.org/license-info), действующие на дату публикации этого документа. Пожалуйста, внимательно ознакомьтесь с этими документами, так как они описывают ваши права и ограничения в отношении этого документа. Компоненты кода, извлеченные из этого документа, должны включать в себя текст упрощенной лицензии BSD, как описано в разделе 4.e Правил доверия, и предоставляются без гарантии, как описано в упрощенной лицензии BSD.

1. Введение

Протокол передачи гипертекста (HTTP) является чрезвычайно успешным протоколом. Однако то, как HTTP/1.1 использует базовый транспорт ([RFC7230 #], раздел 6), имеет несколько характеристик, которые оказывают негативное общее влияние на производительность приложений сегодня.

В частности, HTTP / 1.0 позволял выполнять только один запрос за один раз для данного TCP-соединения. HTTP/1.1 добавил конвейерную обработку запросов, но это только частично адресованный параллелизм запросов и все еще страдает от блокировки заголовка строки. Таким образом, клиенты HTTP / 1.0 и HTTP/1.1, которым необходимо выполнять много запросов, используют несколько соединений с сервером для достижения параллелизма и, следовательно, уменьшения задержки.

Кроме того, поля заголовка HTTP часто повторяются и многословны, вызывая ненужный сетевой трафик, а также вызывая быстрое заполнение начального окна перегрузки TCP [TCP]. Это может привести к чрезмерной задержке при выполнении нескольких запросов для нового соединения TCP.

HTTP/2 решает эти проблемы путем определения оптимизированного сопоставления семантики HTTP с базовым соединением. В частности, он позволяет чередовать сообщения запроса и ответа по одному и тому же соединению и использует эффективное кодирование для полей заголовка HTTP. Это также позволяет назначать приоритеты запросам, позволяя более важным запросам выполняться быстрее, что еще больше повышает производительность.

Полученный протокол более дружественен для сети, поскольку можно использовать меньше TCP-соединений по сравнению с HTTP / 1.x. Это означает меньшую конкуренцию с другими потоками и более длительные соединения, что, в свою очередь, приводит к лучшему использованию доступной емкости сети.

Наконец, HTTP/2 также обеспечивает более эффективную обработку сообщений за счет использования двоичного фрейма сообщения.

2. Обзор протокола HTTP/2

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

Базовый блок протокола в HTTP/2 — это фрейм (раздел 4.1). Каждый тип кадра служит разным целям. Например, фреймы HEADERS и DATA образуют основу HTTP-запросов и ответов (раздел 8.1); другие типы фреймов, такие как SETTINGS, WINDOW_UPDATE и PUSH_PROMISE, используются для поддержки других функций HTTP/2.

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

Управление потоками и установление приоритетов обеспечивают возможность эффективного использования мультиплексированных потоков. Управление потоком (раздел 5.2) помогает обеспечить передачу только тех данных, которые могут использоваться приемником. Приоритизация (раздел 5.3) гарантирует, что ограниченные ресурсы могут быть направлены в первую очередь к наиболее важным потокам.

HTTP/2 добавляет новый режим взаимодействия, при котором сервер может отправлять ответы клиенту (раздел 8.2). Проталкивание сервера позволяет серверу спекулятивно посылать клиенту данные, которые, как ожидает сервер, клиенту понадобится, компенсируя некоторое использование сети с потенциальным увеличением задержки. Сервер делает это, синтезируя запрос, который он отправляет как кадр PUSH_PROMISE. Затем сервер может отправить ответ на синтетический запрос в отдельном потоке.

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

2.1. Организация документов

Спецификация HTTP/2 разделена на четыре части:

  • Запуск HTTP/2 (раздел 3) описывает, как инициируется соединение HTTP/2.
  • Уровни фрейма (раздел 4) и потока (раздел 5) описывают, как кадры HTTP/2 структурируются и формируются в мультиплексированные потоки.
  • Определения фрейма (раздел 6) и ошибок (раздел 7) содержат подробные сведения о фрейме и типах ошибок, используемых в HTTP/2.
  • Отображения HTTP (раздел 8) и дополнительные требования (раздел 9) описывают, как семантика HTTP выражается с использованием фреймов и потоков.

Хотя некоторые концепции уровня фрейма и потока изолированы от HTTP, эта спецификация не определяет полностью общий уровень фрейма. Уровни кадров и потоков адаптированы к требованиям протокола HTTP и проталкивания сервера.

2.2. Условные обозначения и терминология

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

1. ОБЯЗАН — MUST. Это слово или термины «ТРЕБУЕТСЯ — REQUIRED» или «ДОЛЖЕН — SHALL» означают, что определение является абсолютным требованием спецификации.

2. НЕ ОБЯЗАН — MUST NOT. Эта фраза или фраза «НЕ ДОЛЖЕН — SHALL NOT» означают, что определение является абсолютным запретом спецификации.

3. СЛЕДУЕТ — SHOULD. Это слово или прилагательное «РЕКОМЕНДУЕТСЯ — RECOMMENDED» означают, что могут существовать веские причины в определенных обстоятельствах игнорировать конкретный элемент, но все последствия должны быть поняты и тщательно взвешены, прежде чем выбрать другой курс.

4. НЕ СЛЕДУЕТ — SHOULD NOT. Эта фраза или фраза «НЕ РЕКОМЕНДУЕТСЯ — NOT RECOMMENDED» означают, что могут существовать веские причины в определенных обстоятельствах, когда конкретное поведение является приемлемым или даже полезным, но все последствия должны быть поняты, а случай тщательно взвешен, прежде чем реализовывать какое-либо поведение. описано с этим ярлыком.

5. ВОЗМОЖЕН — MAY. Это слово, или прилагательное «ДОПОЛНИТЕЛЬНО — OPTIONAL», означает, что предмет действительно необязателен. Один продавец может включить товар, потому что этого требует конкретный рынок, или потому что продавец чувствует, что он улучшает продукт, в то время как другой продавец может опустить тот же товар. Реализация, которая не включает в себя конкретную опцию, «ОБЯЗАН — MUST» быть подготовлена ​​к взаимодействию с другой реализацией, которая включает опцию, хотя, возможно, с уменьшенной функциональностью. В том же духе реализация, которая включает конкретную опцию, «ОБЯЗАН — MUST» быть подготовлена ​​к взаимодействию с другой реализацией, которая не включает эту опцию (за исключением, конечно, функции, предоставляемой опцией).

Ключевое слово «УСТАРЕЛО» в этом документе относится к операции, атрибуту или значению, которые НЕ ДОЛЖНЫ использоваться или поддерживаться в новых реализациях.

Все числовые значения находятся в сетевом порядке байтов. Значения не подписаны, если не указано иное. Литеральные значения предоставляются в десятичном или шестнадцатеричном виде, в зависимости от ситуации. Шестнадцатеричные литералы имеют префикс «0x», чтобы отличать их от десятичных литералов.

Используются следующие термины:

client (клиент): конечная точка, которая инициирует соединение HTTP/2. Клиенты отправляют HTTP-запросы и получают HTTP-ответы.

connection (соединение): соединение транспортного уровня между двумя конечными точками.

connection error (ошибка соединения): ошибка, которая влияет на все соединение HTTP/2.

endpoint (конечная точка): либо клиент, либо сервер соединения.

frame (кадр): наименьшая единица связи в соединении HTTP/2, состоящая из заголовка и последовательности октетов переменной длины, структурированных в соответствии с типом кадра.

peer (сверстник): конечная точка. При обсуждении конкретной конечной точки «сверстник» относится к конечной точке, удаленной от основного предмета обсуждения.

receiver (приемник): конечная точка, которая получает кадры.

sender (отправитель): конечная точка, которая передает кадры.

server (сервер): конечная точка, которая принимает соединение HTTP/2. Серверы получают HTTP-запросы и отправляют HTTP-ответы.

stream (поток): двунаправленный поток кадров в соединении HTTP/2.

stream error (ошибка потока): ошибка отдельного потока HTTP/2.

Наконец, термины «gateway — шлюз», «intermediary — посредник», «proxy — прокси» и «tunnel — туннель» определены в разделе 2.3 [RFC7230 #]. Посредники действуют как клиент и сервер в разное время.

Термин «payload body — тело полезной нагрузки» определен в разделе 3.3 [RFC7230 #].

3. Запуск HTTP/2

HTTP/2-соединение — это протокол прикладного уровня, работающий поверх TCP-соединения ([TCP]). Клиент является инициатором TCP-соединения.

HTTP/2 использует те же схемы URI «http» и «https», которые используются в HTTP/1.1. HTTP/2 использует одни и те же номера портов по умолчанию: 80 для URI «http» и 443 для URI «https». В результате реализации, обрабатывающие запросы для целевых URI ресурсов, таких как «http://example.org/foo» или «https://example.com/bar», должны сначала обнаружить, является ли вышестоящий сервер (непосредственный узел, с которым клиент желает установить соединение) поддерживает HTTP/2.

Средства, с помощью которых определяется поддержка HTTP/2, различаются для URI «http» и «https». Обнаружение для «http» URI описано в разделе 3.2. Обнаружение URI «https» описано в разделе 3.3.

3.1. Идентификация версии HTTP/2

Протокол, определенный в этом документе, имеет два идентификатора:

  • Строка «h2» идентифицирует протокол, в котором HTTP/2 использует безопасность транспортного уровня (TLS) [TLS12]. Этот идентификатор используется в поле [TLS-ALPN] расширения согласования протокола прикладного уровня TLS и в любом месте, где идентифицирован HTTP/2 по TLS. Строка «h2» сериализуется в идентификатор протокола ALPN в виде двухоктетной последовательности: 0x68, 0x32.
  • Строка «h2c» идентифицирует протокол, в котором HTTP/2 выполняется поверх открытого текста TCP. Этот идентификатор используется в поле заголовка обновления HTTP/1.1 и в любом месте, где идентифицируется HTTP/2 по TCP. Строка «h2c» зарезервирована из пространства идентификаторов ALPN, но описывает протокол, который не использует TLS.

Согласование «h2» или «h2c» подразумевает использование семантики транспорта, безопасности, кадрирования и сообщения, описанной в этом документе.

3.2. Запуск HTTP/2 для http-URI

Клиент, который делает запрос на «http» URI без предварительного знания о поддержке HTTP/2 при следующем переходе, использует механизм обновления HTTP (Раздел 6.7 [RFC7230 #]). Клиент делает это, отправляя запрос HTTP/1.1, который включает в себя поле заголовка Upgrade с токеном «h2c». Такой запрос HTTP/1.1 ДОЛЖЕН включать ровно одно поле заголовка HTTP2-Settings (раздел 3.2.1).

Например:

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

Запросы, содержащие тело полезной нагрузки, ДОЛЖНЫ быть отправлены полностью, прежде чем клиент сможет отправить кадры HTTP/2. Это означает, что большой запрос может заблокировать использование соединения, пока оно не будет полностью отправлено.

Если одновременность начального запроса с последующими запросами важна, запрос OPTIONS может использоваться для выполнения обновления до HTTP/2 за счет дополнительного туда-обратно.

Сервер, который не поддерживает HTTP/2, может ответить на запрос, как если бы поле заголовка обновления отсутствовало:

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
...

Сервер ДОЛЖЕН игнорировать токен «h2» в поле заголовка обновления. Присутствие токена с «h2» подразумевает HTTP/2 по TLS, который вместо этого согласовывается, как описано в разделе 3.3.

Сервер, который поддерживает HTTP/2, принимает обновление с ответом 101 (Switching Protocols). После пустой строки, которая завершает ответ 101, сервер может начать отправку кадров HTTP/2. Эти кадры ДОЛЖНЫ включать ответ на запрос, который инициировал обновление.

Например:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...

Первый HTTP/2-кадр, отправленный сервером, ДОЛЖЕН быть предисловием к соединению с сервером (раздел 3.5), состоящим из кадра SETTINGS (раздел 6.5). После получения ответа 101 клиент ДОЛЖЕН отправить предисловие к соединению (раздел 3.5), которое включает в себя кадр SETTINGS.

Запрос HTTP/1.1, отправляемый до обновления, получает идентификатор потока 1 (см. Раздел 5.1.1) со значениями приоритета по умолчанию (раздел 5.3.5). Поток 1 неявно «полузакрыт» от клиента к серверу (см. Раздел 5.1), поскольку запрос выполняется как запрос HTTP/1.1. После установления соединения HTTP/2 поток 1 используется для ответа.

3.2.1. Поле заголовка настроек HTTP2

Запрос, который обновляет HTTP/1.1 до HTTP/2, ДОЛЖЕН включать ровно одно поле заголовка «HTTP2-Settings». Поле заголовка HTTP2-Settings — это поле заголовка, относящееся к соединению, которое включает параметры, которые управляют соединением HTTP/2, предоставляемое в ожидании того, что сервер примет запрос на обновление.

HTTP2-Settings = token68

Сервер НЕ ДОЛЖЕН обновлять соединение до HTTP/2, если это поле заголовка отсутствует или присутствует более одного. Сервер НЕ ДОЛЖЕН отправлять это поле заголовка.

Содержимое поля заголовка HTTP2-Settings представляет собой полезную нагрузку кадра SETTINGS (раздел 6.5), закодированного в виде строки base64url (то есть кодировки Base64, безопасной для URL и имен файлов, описанной в разделе 5 [RFC4648 #], с любым завершающие символы ‘=’ опущены). Производство ABNF [RFC5234 #] для «token68» определено в разделе 2.1 [RFC7235 #].

Поскольку обновление предназначено только для непосредственного подключения, клиент, отправляющий поле заголовка HTTP2-настройки, ДОЛЖЕН также отправить «HTTP2-настройки» в качестве параметра подключения в поле заголовка подключения, чтобы предотвратить его пересылку (см. Раздел 6.1 [RFC7230 #]).

Сервер декодирует и интерпретирует эти значения так же, как и любой другой кадр SETTINGS. Явное подтверждение этих настроек (раздел 6.5.3) не требуется, поскольку ответ 101 служит неявным подтверждением. Предоставление этих значений в запросе на обновление дает клиенту возможность предоставить параметры до получения каких-либо кадров с сервера.

3.3. Запуск HTTP/2 для URI «https»

Клиент, который отправляет запрос на URI «https», использует TLS [TLS12] с расширением согласования протокола прикладного уровня (ALPN) [TLS-ALPN].

HTTP/2 по TLS использует идентификатор протокола «h2». Идентификатор протокола «h2c» НЕ ДОЛЖЕН быть отправлен клиентом или выбран сервером; идентификатор протокола «h2c» описывает протокол, который не использует TLS.

После завершения согласования TLS и клиент, и сервер ДОЛЖНЫ отправить предисловие к соединению (раздел 3.5).

3.4. Запуск HTTP/2 с предварительными знаниями

Клиент может узнать, что конкретный сервер поддерживает HTTP/2 другими способами. Например, [ALT-SVC] описывает механизм для рекламы этой возможности.

Клиент ДОЛЖЕН отправить предисловие к соединению (раздел 3.5), а затем МОЖЕТ немедленно отправить кадры HTTP/2 на такой сервер; серверы могут идентифицировать эти соединения по наличию предисловия к соединению. Это влияет только на установление соединений HTTP/2 через открытый текст TCP; реализации, которые поддерживают HTTP/2 по TLS, ДОЛЖНЫ использовать согласование протокола в TLS [TLS-ALPN].

Кроме того, сервер ДОЛЖЕН отправить предисловие к соединению (раздел 3.5).

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

3.5. HTTP/2 Предисловие к подключению

В HTTP/2 каждая конечная точка должна отправлять предисловие к соединению в качестве окончательного подтверждения используемого протокола и устанавливать начальные настройки для соединения HTTP/2. Клиент и сервер отправляют разные предисловия к соединению.

Предисловие к клиентскому соединению начинается с последовательности из 24 октетов, которая в шестнадцатеричной форме имеет вид:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

То есть предисловие к соединению начинается со строки «PRI * HTTP / 2.0 \ r \ n \ r \ nSM \ r \ n \ r \ n»). За этой последовательностью ДОЛЖЕН следовать кадр SETTINGS (раздел 6.5), который МОЖЕТ быть пустым. Клиент отправляет предисловие к клиентскому соединению сразу же после получения ответа 101 (Коммутационные протоколы) (указывающего на успешное обновление) или в качестве первых октетов данных приложения для соединения TLS. При запуске соединения HTTP/2 с предшествующим знанием о поддержке сервером протокола, предисловие клиентского соединения отправляется после установления соединения.

Примечание. Предисловие к клиентскому соединению выбрано таким образом, чтобы большая часть серверов и посредников HTTP/1.1 или HTTP / 1.0 не пыталась обрабатывать дополнительные кадры. Обратите внимание, что это не решает проблемы, поднятые в [TALKING].

Предисловие к соединению с сервером состоит из потенциально пустого кадра SETTINGS (раздел 6.5), который ДОЛЖЕН быть первым кадром, который сервер отправляет в соединении HTTP/2.

Кадры SETTINGS, полученные от однорангового узла как часть предисловия к соединению, ДОЛЖНЫ быть подтверждены (см. Раздел 6.5.3) после отправки предисловия к соединению.

Чтобы избежать ненужных задержек, клиентам разрешается отправлять дополнительные кадры на сервер сразу после отправки предисловия к соединению клиента, не дожидаясь получения предисловия к соединению с сервером. Важно отметить, однако, что кадр НАСТРОЙКИ предисловия к соединению с сервером может включать параметры, которые обязательно изменяют то, как клиент должен обмениваться данными с сервером. Ожидается, что после получения кадра SETTINGS клиент выполнит любые установленные параметры. В некоторых конфигурациях сервер может передавать НАСТРОЙКИ, прежде чем клиент отправит дополнительные кадры, предоставляя возможность избежать этой проблемы.

Клиенты и серверы ДОЛЖНЫ рассматривать неверное предисловие к соединению как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR. Кадр GOAWAY (раздел 6.8) МОЖЕТ быть опущен в этом случае, поскольку неверное предисловие указывает, что узел не использует HTTP/2.

4. HTTP-кадры

Как только соединение HTTP/2 установлено, конечные точки могут начать обмен кадрами.

4.1. Формат кадра

Все кадры начинаются с фиксированного 9-октетного заголовка, за которым следует полезная нагрузка переменной длины.

Рисунок 1 - Структура кадра
Рисунок 1 — Структура кадра

Поля заголовка фрейма определены как:

Length (Длина): длина полезной нагрузки кадра, выраженная как 24-разрядное целое число без знака. Значения, превышающие 2^14 (16 384), НЕ ДОЛЖНЫ отправляться, если получатель не установил большее значение для SETTINGS_MAX_FRAME_SIZE.

9 октетов заголовка кадра не включены в это значение.

Type (Тип): 8-битный тип кадра. Тип кадра определяет формат и семантику кадра. Реализации ДОЛЖНЫ игнорировать и отбрасывать любой фрейм с неизвестным типом.

Flags (Флаги): 8-битное поле, зарезервированное для логических флагов, специфичных для типа кадра. Флаги назначают семантику, специфичную для указанного типа кадра. Флаги, которые не имеют определенной семантики для конкретного типа кадра, ДОЛЖНЫ игнорироваться и ДОЛЖНЫ быть оставлены неустановленными (0x0) при отправке.

R: зарезервированное 1-битное поле. Семантика этого бита не определена, и бит ДОЛЖЕН оставаться неустановленным (0x0) при отправке и ДОЛЖЕН игнорироваться при приеме.

Stream Identifier (Идентификатор потока): идентификатор потока (см. Раздел 5.1.1), выраженный как 31-разрядное целое число без знака. Значение 0x0 зарезервировано для кадров, которые связаны с соединением в целом, а не с отдельным потоком.

Структура и содержание полезной нагрузки кадра полностью зависит от типа кадра.

4.2. Размер кадра

Размер полезной нагрузки кадра ограничен максимальным размером, который получатель объявляет в настройке SETTINGS_MAX_FRAME_SIZE. Этот параметр может иметь любое значение от 2 ^ 14 (16 384) до 2 ^ 24-1 (16 777 215) октетов включительно.

Все реализации ДОЛЖНЫ быть способны принимать и минимально обрабатывать кадры длиной до 2 ^ 14 октетов, а также заголовок 9-октетного кадра (раздел 4.1). Размер заголовка кадра не учитывается при описании размеров кадра.

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

Конечная точка ДОЛЖНА отправить код ошибки FRAME_SIZE_ERROR, если кадр превышает размер, определенный в SETTINGS_MAX_FRAME_SIZE, превышает любой предел, определенный для типа кадра, или слишком мал, чтобы содержать обязательные данные кадра. Ошибка размера кадра в кадре, которая может изменить состояние всего соединения, ДОЛЖНА рассматриваться как ошибка соединения (раздел 5.4.1); это включает в себя любой кадр, несущий блок заголовка (раздел 4.3) (то есть HEADERS, PUSH_PROMISE и CONTINUATION), SETTINGS и любой кадр с идентификатором потока 0.

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

4.3. Сжатие заголовка и декомпрессия

Как и в HTTP/1, поле заголовка в HTTP/2 — это имя с одним или несколькими связанными значениями. Поля заголовка используются в HTTP-запросах и ответных сообщениях, а также в операциях push-уведомлений сервера (см. Раздел 8.2).

Списки заголовков представляют собой наборы из нуля или более полей заголовка. При передаче по соединению список заголовков сериализуется в блок заголовков с использованием сжатия заголовка HTTP [COMPRESSION]. Затем сериализованный блок заголовка разделяется на одну или несколько последовательностей октетов, называемых фрагментами блока заголовка, и передается в полезной нагрузке кадров HEADERS (раздел 6.2), PUSH_PROMISE (раздел 6.6) или CONTINUATION (раздел 6.10).

Поле заголовка Cookie [COOKIE] специально обрабатывается HTTP-отображением (см. Раздел 8.1.2.5).

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

Полный блок заголовка состоит из:

  • один кадр HEADERS или PUSH_PROMISE с установленным флагом END_HEADERS
  • кадр HEADERS или PUSH_PROMISE с очищенным флагом END_HEADERS и одним или несколькими кадрами CONTINUATION, где последний кадр CONTINUATION имеет установленный флаг END_HEADERS.

Сжатие заголовка с состоянием. Один контекст сжатия и один контекст распаковки используются для всего соединения. Ошибка декодирования в блоке заголовка ДОЛЖНА рассматриваться как ошибка соединения (раздел 5.4.1) типа COMPRESSION_ERROR.

Каждый блок заголовка обрабатывается как отдельный блок. Блоки заголовка ДОЛЖНЫ передаваться как непрерывная последовательность кадров без чередующихся кадров любого другого типа или из любого другого потока. Последний кадр в последовательности кадров HEADERS или CONTINUATION имеет установленный флаг END_HEADERS. Последний кадр в последовательности кадров PUSH_PROMISE или CONTINUATION имеет установленный флаг END_HEADERS. Это позволяет блоку заголовка быть логически эквивалентным одному кадру.

Фрагменты блока заголовка могут быть отправлены только как полезные данные кадров HEADERS, PUSH_PROMISE или CONTINUATION, потому что эти кадры переносят данные, которые могут изменять контекст сжатия, поддерживаемый получателем. Конечная точка, получающая кадры HEADERS, PUSH_PROMISE или CONTINUATION, должна повторно собрать блоки заголовка и выполнить декомпрессию, даже если кадры должны быть отброшены. Приемник ДОЛЖЕН разорвать соединение с ошибкой соединения (раздел 5.4.1) типа COMPRESSION_ERROR, если он не распаковывает блок заголовка.

5. Потоки и мультиплексирование

«Stream» (Поток) — это независимая двунаправленная последовательность кадров, которыми обмениваются клиент и сервер в рамках соединения HTTP/2. Потоки имеют несколько важных характеристик:

  • Одно соединение HTTP/2 может содержать несколько одновременно открытых потоков, причем чередование конечных точек чередует кадры из нескольких потоков.
  • Потоки могут устанавливаться и использоваться в одностороннем порядке или совместно использоваться клиентом или сервером.
  • Потоки могут быть закрыты любой конечной точкой.
  • Порядок, в котором кадры отправляются в потоке, имеет большое значение. Получатели обрабатывают кадры в порядке их получения. В частности, порядок кадров HEADERS и DATA является семантически значимым.
  • Потоки идентифицируются целым числом. Идентификаторы потока назначаются потокам конечной точкой, инициирующей поток.

5.1. Состояния потока

Жизненный цикл потока показан на рисунке 2.

Рисунок 2 - Состояния потока
Рисунок 2 — Состояния потока

send: конечная точка отправляет этот кадр
recv: конечная точка получает этот кадр

H: рамка HEADERS (с подразумеваемыми продолжениями)
PP: кадр PUSH_PROMISE (с подразумеваемыми продолжениями)
ES: END_STREAM флаг
R: RST_STREAM кадр

Обратите внимание, что на этой диаграмме показаны переходы состояний потока, а также кадры и флаги, которые влияют только на эти переходы. В этом отношении кадры ПРОДОЛЖЕНИЯ не приводят к переходам состояний; они фактически являются частью HEADERS или PUSH_PROMISE, за которыми они следуют.

В целях перехода состояний флаг END_STREAM обрабатывается как отдельное событие для кадра, который его несет; кадр HEADERS с установленным флагом END_STREAM может вызвать два перехода состояний.

Обе конечные точки имеют субъективное представление о состоянии потока, которое может различаться при передаче кадров. Конечные точки не координируют создание потоков; они создаются в одностороннем порядке любой конечной точкой. Негативные последствия несоответствия в состояниях ограничиваются «закрытым» состоянием после отправки RST_STREAM, где кадры могут быть получены в течение некоторого времени после закрытия.

Состояние потока — idle (ожидание)

Все потоки запускаются в состоянии «idle — ожидание».

Следующие переходы действительны из этого состояния:

  • При отправке или получении кадра HEADERS поток становится «открытым». Идентификатор потока выбирается, как описано в разделе 5.1.1. Тот же кадр HEADERS также может привести к тому, что поток немедленно станет «полузакрытым».
  • Отправка кадра PUSH_PROMISE в другой поток резервирует незанятый поток, который будет идентифицирован для последующего использования. Состояние потока для зарезервированного потока переходит в «зарезервированный (локальный)».
  • При получении кадра PUSH_PROMISE в другом потоке резервируется незанятый поток, который идентифицируется для последующего использования. Состояние потока для зарезервированного потока переходит в «зарезервированный (удаленный)».
  • Обратите внимание, что кадр PUSH_PROMISE не отправляется в свободном потоке, но ссылается на вновь зарезервированный поток в поле идентификатора обещанного потока.

Получение любого кадра, отличного от HEADERS или PRIORITY в потоке в этом состоянии, ДОЛЖНО рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Состояние потока — reserved (local)

Поток в «зарезервированном (локальном)» состоянии — это поток, который был обещан при отправке кадра PUSH_PROMISE. Кадр PUSH_PROMISE резервирует незанятый поток, связывая поток с открытым потоком, который был инициирован удаленным узлом (см. Раздел 8.2).

В этом состоянии возможны только следующие переходы:

  • Конечная точка может отправлять кадр HEADERS. Это заставляет поток открываться в «полузакрытом (удаленном)» состоянии.
  • Любая конечная точка может отправить кадр RST_STREAM, чтобы поток стал «закрытым». Это освобождает поток бронирования.

Конечная точка НЕ ДОЛЖНА отправлять кадры любого типа, кроме HEADERS, RST_STREAM или PRIORITY в этом состоянии.

В этом состоянии МОЖЕТ быть принят кадр PRIORITY или WINDOW_UPDATE. Получение любого типа фрейма, кроме RST_STREAM, PRIORITY или WINDOW_UPDATE, в потоке в этом состоянии ДОЛЖНО рассматриваться как ошибка соединения (Раздел 5.4.1) типа PROTOCOL_ERROR.

Состояние потока — reserved (remote)

Поток в состоянии «зарезервирован (удален)» зарезервирован удаленным узлом.

В этом состоянии возможны только следующие переходы:

  • При получении кадра HEADERS поток переходит в «полузакрытый (локальный)».
  • Любая конечная точка может отправить кадр RST_STREAM, чтобы поток стал «закрытым». Это освобождает поток бронирования.

Конечная точка МОЖЕТ отправить кадр ПРИОРИТЕТА в этом состоянии, чтобы перераспределить зарезервированный поток. Конечная точка НЕ ДОЛЖНА отправлять кадры любого типа, кроме RST_STREAM, WINDOW_UPDATE или PRIORITY, в этом состоянии.

Получение любого типа фрейма, кроме HEADERS, RST_STREAM или PRIORITY в потоке в этом состоянии, ДОЛЖНО рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Состояние потока — open

Поток в состоянии «открыто» может использоваться обоими узлами для отправки кадров любого типа. В этом состоянии отправляющие узлы соблюдают объявленные пределы контроля потока на уровне потока (раздел 5.2).

Из этого состояния любая конечная точка может отправить кадр с установленным флагом END_STREAM, который заставляет поток переходить в одно из «полузакрытых» состояний. Конечная точка, отправляющая флаг END_STREAM, приводит к тому, что состояние потока становится «полузакрытым (локальным)»; конечная точка, получающая флаг END_STREAM, приводит к тому, что состояние потока становится «полузакрытым (удаленным)».

Любая конечная точка может отправить кадр RST_STREAM из этого состояния, в результате чего он немедленно переходит в «закрытый».

Состояние потока — half-closed (local)

Поток, который находится в состоянии «полузакрытого (локального)», не может использоваться для отправки кадров, отличных от WINDOW_UPDATE, PRIORITY и RST_STREAM.

Поток переходит из этого состояния в «закрытое», когда принимается кадр, содержащий флаг END_STREAM, или когда один из узлов отправляет кадр RST_STREAM.

Конечная точка может получить любой тип кадра в этом состоянии. Предоставление кредита управления потоком с использованием кадров WINDOW_UPDATE необходимо для продолжения приема кадров с управлением потоком. В этом состоянии получатель может игнорировать кадры WINDOW_UPDATE, которые могут появиться в течение короткого периода времени после отправки кадра с флагом END_STREAM.

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

Состояние потока — half-closed (remote)

Поток, который является «полузакрытым (удаленным)», больше не используется одноранговым узлом для отправки кадров. В этом состоянии конечная точка больше не обязана поддерживать окно управления потоком в приемнике.

Если конечная точка получает дополнительные кадры, кроме WINDOW_UPDATE, PRIORITY или RST_STREAM, для потока, находящегося в этом состоянии, она ДОЛЖНА ответить ошибкой потока (раздел 5.4.2) типа STREAM_CLOSED.

Поток, который является «полузакрытым (удаленным)», может использоваться конечной точкой для отправки кадров любого типа. В этом состоянии конечная точка продолжает соблюдать объявленные пределы управления потоком на уровне потока (раздел 5.2).

Поток может перейти из этого состояния в «закрытое», отправив кадр, содержащий флаг END_STREAM, или когда один из узлов отправляет кадр RST_STREAM.

Состояние потока — closed

Закрытое состояние — это состояние терминала.

Конечная точка НЕ ​​ДОЛЖНА отправлять кадры, кроме ПРИОРИТЕТА, в закрытом потоке. Конечная точка, которая получает любой кадр, отличный от PRIORITY, после получения RST_STREAM ДОЛЖНА трактовать это как ошибку потока (раздел 5.4.2) типа STREAM_CLOSED. Аналогично, конечная точка, которая принимает любые кадры после получения кадра с установленным флагом END_STREAM, ДОЛЖНА трактовать это как ошибку соединения (раздел 5.4.1) типа STREAM_CLOSED, если только кадр не разрешен, как описано ниже.

Кадры WINDOW_UPDATE или RST_STREAM могут приниматься в этом состоянии в течение короткого периода времени после отправки кадра DATA или HEADERS, содержащего флаг END_STREAM. До тех пор, пока удаленный узел не получит и не обработает RST_STREAM или кадр, несущий флаг END_STREAM, он может отправлять кадры этих типов. Конечные точки ДОЛЖНЫ игнорировать кадры WINDOW_UPDATE или RST_STREAM, полученные в этом состоянии, хотя конечные точки МОГУТ выбрать обработку кадров, прибывающих через значительное время после отправки END_STREAM, как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Приоритетные кадры могут быть отправлены в закрытых потоках для определения приоритетов потоков, которые зависят от закрытого потока. Конечные точки ДОЛЖНЫ обрабатывать кадры PRIORITY, хотя их можно игнорировать, если поток был удален из дерева зависимостей (см. Раздел 5.3.4).

Если это состояние достигается в результате отправки кадра RST_STREAM, то одноранговый узел, который получает RST_STREAM, возможно, уже отправил или поставил в очередь на отправку кадры в потоке, которые не могут быть отозваны. Конечная точка ДОЛЖНА игнорировать кадры, которые она получает в закрытых потоках после того, как она отправила кадр RST_STREAM. Конечная точка МОЖЕТ выбрать ограничение периода, в течение которого она игнорирует кадры, и обрабатывать кадры, поступающие после этого времени, как ошибочные.

Контролируемые потоком кадры (то есть DATA), полученные после отправки RST_STREAM, учитываются в окне управления потоком соединения. Даже если эти кадры могут быть проигнорированы, поскольку они отправляются до того, как отправитель получает RST_STREAM, отправитель будет считать кадры для подсчета в окне управления потоком.

Конечная точка может получить кадр PUSH_PROMISE после отправки RST_STREAM. PUSH_PROMISE заставляет поток становиться «зарезервированным», даже если связанный поток был сброшен. Следовательно, RST_STREAM необходим для закрытия нежелательного обещанного потока.

 

В отсутствие более конкретных указаний в другом месте этого документа реализации СЛЕДУЕТ трактовать получение кадра, который явно не разрешен в описании состояния, как ошибку соединения (Раздел 5.4.1) типа PROTOCOL_ERROR. Обратите внимание, что ПРИОРИТЕТ может быть отправлен и получен в любом состоянии потока. Кадры неизвестных типов игнорируются.

Пример перехода состояний для обмена запросами / ответами HTTP можно найти в Разделе 8.1. Пример перехода состояний для принудительной отправки сервера можно найти в разделах 8.2.1 и 8.2.2.

5.1.1. Идентификаторы потока

Потоки идентифицируются беззнаковым 31-битным целым числом. Потоки, инициированные клиентом, ДОЛЖНЫ использовать нечетные идентификаторы потока; Инициированные сервером ДОЛЖНЫ использовать четные идентификаторы потока. Нулевой идентификатор потока (0x0) используется для сообщений управления соединением; нулевой идентификатор потока не может быть использован для создания нового потока.

На запросы HTTP/1.1, которые обновлены до HTTP/2 (см. Раздел 3.2), отвечает потоковый идентификатор, равный единице (0x1). После завершения обновления поток 0x1 становится «полузакрытым (локальным)» для клиента. Поэтому поток 0x1 не может быть выбран в качестве нового идентификатора потока клиентом, который обновляется с HTTP/1.1.

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

Первое использование нового идентификатора потока неявно закрывает все потоки в состоянии «бездействия», которые могли быть инициированы этим узлом с более низким значением идентификатора потока. Например, если клиент отправляет кадр HEADERS в потоке 7, не отправляя кадр в потоке 5, тогда поток 5 переходит в «закрытое» состояние, когда первый кадр для потока 7 отправляется или принимается.

Идентификаторы потока не могут быть использованы повторно. Долгоживущие соединения могут привести к тому, что конечная точка исчерпает доступный диапазон идентификаторов потока. Клиент, который не может установить новый идентификатор потока, может установить новое соединение для новых потоков. Сервер, который не может установить новый идентификатор потока, может отправить кадр GOAWAY, чтобы клиент был вынужден открыть новое соединение для новых потоков.

5.1.2. Поток параллелизма

Одноранговый узел может ограничить количество одновременно активных потоков, используя параметр SETTINGS_MAX_CONCURRENT_STREAMS (см. Раздел 6.5.2) в кадре SETTINGS. Параметр максимального числа одновременных потоков специфичен для каждой конечной точки и применяется только к узлу, который получает параметр. То есть клиенты указывают максимальное количество одновременных потоков, которые может инициировать сервер, а серверы указывают максимальное количество одновременных потоков, которые может инициировать клиент.

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

Конечные точки НЕ ДОЛЖНЫ превышать лимит, установленный их узлом. Конечная точка, которая получает кадр HEADERS, который приводит к превышению заявленного предела одновременного потока, ДОЛЖНА трактовать это как ошибку потока (раздел 5.4.2) типа PROTOCOL_ERROR или REFUSED_STREAM. Выбор кода ошибки определяет, желает ли конечная точка включить автоматическую повторную попытку (подробнее см. в разделе 8.1.4).

Конечная точка, которая желает уменьшить значение SETTINGS_MAX_CONCURRENT_STREAMS до значения, которое меньше текущего количества открытых потоков, может либо закрыть потоки, которые превышают новое значение, либо разрешить потокам завершиться.

5.2. Управление потоком

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

HTTP/2 обеспечивает управление потоком посредством использования фрейма WINDOW_UPDATE (раздел 6.9).

5.2.1. Принципы управления потоком

Управление потоком HTTP/2 имеет целью позволить использовать различные алгоритмы управления потоком, не требуя изменений протокола. Управление потоком в HTTP/2 имеет следующие характеристики:

  • 1. Управление потоком зависит от соединения. Оба типа управления потоком находятся между конечными точками одного перехода, а не по всему сквозному пути.
  • 2. Управление потоком основано на кадрах WINDOW_UPDATE. Получатели объявляют, сколько октетов они готовы получить в потоке и для всего соединения. Это кредитная схема.
  • 3. Управление потоком является направленным с полным контролем, обеспечиваемым приемником. Получатель МОЖЕТ установить любой размер окна, который он желает, для каждого потока и для всего соединения. Отправитель ДОЛЖЕН соблюдать ограничения управления потоком, наложенные получателем. Клиенты, серверы и посредники независимо объявляют свое окно управления потоком как получателя и соблюдают ограничения управления потоком, установленные их одноранговым узлом при отправке.
  • 4. Начальное значение для окна управления потоком составляет 65 535 октетов как для новых потоков, так и для общего соединения.
  • 5. Тип кадра определяет, применяется ли управление потоком к кадру. Из кадров, указанных в этом документе, только кадры DATA подлежат управлению потоком; все остальные типы кадров не занимают места в объявленном окне управления потоком. Это гарантирует, что важные контрольные кадры не блокируются управлением потоком.
  • 6. Управление потоком невозможно отключить.
  • 7. HTTP/2 определяет только формат и семантику фрейма WINDOW_UPDATE (раздел 6.9). В этом документе не указано, как получатель решает, когда отправлять этот кадр или значение, которое он отправляет, а также не указывается, как отправитель выбирает отправку пакетов. Реализации могут выбрать любой алгоритм, который соответствует их потребностям.

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

5.2.2. Надлежащее использование контроля потока

Управление потоком данных определено для защиты конечных точек, которые работают в условиях ограниченных ресурсов. Например, прокси-сервер должен разделять память между многими соединениями, а также может иметь медленное восходящее соединение и быстрое нисходящее соединение. Управление потоком данных рассматривает случаи, когда получатель не может обрабатывать данные в одном потоке, но хочет продолжить обработку других потоков в том же соединении.

Развертывания, не требующие этой возможности, могут объявить окно управления потоком максимального размера (2 ^ 31-1) и могут поддерживать это окно, отправляя кадр WINDOW_UPDATE при получении любых данных. Это эффективно отключает управление потоком для этого приемника. И наоборот, отправитель всегда подчиняется окну управления потоком, объявленному получателем.

Развертывания с ограниченными ресурсами (например, памятью) могут использовать управление потоком, чтобы ограничить объем памяти, который может потреблять одноранговый узел. Однако обратите внимание, что это может привести к неоптимальному использованию доступных сетевых ресурсов, если управление потоком включено без знания продукта с пропускной способностью полосы пропускания (см. [RFC7323 #]).

Даже при полной осведомленности о текущем продукте с задержкой полосы пропускания реализация управления потоком может быть затруднена. При использовании управления потоком получатель ДОЛЖЕН своевременно читать из приемного буфера TCP. Невыполнение этого требования может привести к тупику, когда критические кадры, такие как WINDOW_UPDATE, не читаются и не обрабатываются.

5.3. Приоритет потока

Клиент может назначить приоритет новому потоку, включив информацию о приоритетах в кадр HEADERS (раздел 6.2), который открывает поток. В любое другое время кадр ПРИОРИТЕТ (Раздел 6.3) может использоваться для изменения приоритета потока.

Цель расстановки приоритетов — позволить конечной точке выражать то, как она предпочитает, чтобы ее одноранговый узел выделял ресурсы при управлении параллельными потоками. Наиболее важно, приоритет может использоваться для выбора потоков для передачи кадров, когда существует ограниченная емкость для отправки.

Для потоков можно назначить приоритеты, помечая их как зависимые от завершения других потоков (раздел 5.3.1). Каждой зависимости присваивается относительный вес, число, которое используется для определения относительной доли доступных ресурсов, которые назначены потокам, зависящим от одного и того же потока.

Явная установка приоритета для потока является входом в процесс расстановки приоритетов. Это не гарантирует какой-либо конкретный порядок обработки или передачи для потока относительно любого другого потока. Конечная точка не может заставить одноранговый узел обрабатывать параллельные потоки в определенном порядке, используя приоритет. Выражение приоритета, следовательно, только предложение.

Информация о приоритетах может быть опущена в сообщениях. Значения по умолчанию используются до предоставления каких-либо явных значений (раздел 5.3.5).

5.3.1. Зависимости потока

Каждому потоку может быть дана явная зависимость от другого потока. Включение зависимости выражает предпочтение выделять ресурсы для идентифицированного потока, а не для зависимого потока.

Поток, который не зависит ни от какого другого потока, получает зависимость потока от 0x0. Другими словами, несуществующий поток 0 образует корень дерева.

Поток, который зависит от другого потока, является зависимым потоком. Поток, от которого зависит поток, является родительским потоком. Зависимость от потока, который в данный момент отсутствует в дереве, например потока в состоянии «бездействия», приводит к тому, что этому потоку присваивается приоритет по умолчанию (раздел 5.3.5).

При назначении зависимости от другого потока поток добавляется как новая зависимость родительского потока. Зависимые потоки, которые совместно используют одного и того же родителя, не упорядочены по отношению друг к другу. Например, если потоки B и C зависят от потока A, и если поток D создается с зависимостью от потока A, это приводит к порядку зависимости A, за которым следуют B, C и D в любом порядке.

Рисунок 3 - Пример создания зависимостей по умолчанию
Рисунок 3 — Пример создания зависимостей по умолчанию

Эксклюзивный флаг позволяет вставлять новый уровень зависимостей. Флаг исключений приводит к тому, что поток становится единственной зависимостью его родительского потока, в результате чего другие зависимости становятся зависимыми от исключительного потока. В предыдущем примере, если поток D создается с исключительной зависимостью от потока A, это приводит к тому, что D становится родителем зависимости для B и C.

Рисунок 4 - Пример создания исключительной зависимости
Рисунок 4 — Пример создания исключительной зависимости

Внутри дерева зависимостей зависимому потоку СЛЕДУЕТ выделять ресурсы только в том случае, если либо все потоки, от которых он зависит (цепочка родительских потоков до 0x0), закрыты, либо невозможно достичь прогресса в них.

Поток не может зависеть от самого себя. Конечная точка ДОЛЖНА трактовать это как ошибку потока (раздел 5.4.2) типа PROTOCOL_ERROR.

5.3.2. Взвешивание зависимостей

Всем зависимым потокам присваивается целочисленный вес от 1 до 256 (включительно).

Потокам с одним и тем же родительским объектом СЛЕДУЕТ распределять ресурсы пропорционально их весу. Таким образом, если поток B зависит от потока A с весом 4, поток C зависит от потока A с весом 12, и в потоке A не может быть никакого прогресса, в идеале поток B получает одну треть ресурсов, выделенных для потока C.

5.3.3. изменения приоритетов

Приоритеты потоков изменяются с помощью фрейма ПРИОРИТЕТ. Установка зависимости приводит к тому, что поток становится зависимым от идентифицированного родительского потока.

Зависимые потоки перемещаются вместе со своим родительским потоком, если родительский поток перераспределен. Установка зависимости с флагом исключений для переориентированного потока приводит к тому, что все зависимости нового родительского потока становятся зависимыми от переориентированного потока.

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

Например, рассмотрим исходное дерево зависимостей, где B и C зависят от A, D и E зависят от C, а F зависит от D. Если A становится зависимым от D, то D заменяет собой A. Все остальные отношения зависимости остаются то же самое, за исключением F, который становится зависимым от A, если перераспределение является исключительным.

Рисунок 5 - Пример переупорядочения зависимостей
Рисунок 5 — Пример переупорядочения зависимостей

5.3.4. Приоритет государственного управления

Когда поток удаляется из дерева зависимостей, его зависимости могут быть перемещены, чтобы стать зависимыми от родителя закрытого потока. Веса новых зависимостей пересчитываются путем распределения веса зависимости замкнутого потока пропорционально на основе весов его зависимостей.

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

Например, предположим, что потоки A и B совместно используют родительский элемент, а потоки C и D оба зависят от потока A. До удаления потока A, если потоки A и D не могут продолжаться, тогда поток C принимает все ресурсы, выделенные для Поток A. Если поток A удаляется из дерева, вес потока A делится между потоками C и D. Если поток D все еще не может продолжаться, это приводит к тому, что поток C получает уменьшенную долю ресурсов. Для равных начальных весов C получает одну треть, а не половину доступных ресурсов.

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

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

Точно так же потокам, которые находятся в состоянии «ожидания», может быть назначен приоритет или они могут стать родителями других потоков. Это позволяет создать узел группировки в дереве зависимостей, что обеспечивает более гибкие выражения приоритета. Свободные потоки начинаются с приоритета по умолчанию (раздел 5.3.5).

Сохранение информации о приоритете для потоков, которые не учитываются в пределе, установленном SETTINGS_MAX_CONCURRENT_STREAMS, может создать большую нагрузку на состояние для конечной точки. Следовательно, количество сохраняемого состояния приоритетов МОЖЕТ быть ограничено.

Количество дополнительного состояния, которое конечная точка поддерживает для определения приоритетов, может зависеть от нагрузки; при высокой нагрузке состояние приоритетов может быть отброшено для ограничения выделения ресурсов. В крайних случаях конечная точка может даже отбросить состояние приоритезации для активных или зарезервированных потоков. Если применяется ограничение, конечные точки ДОЛЖНЫ поддерживать состояние по крайней мере для такого количества потоков, которое допускается их настройкой для SETTINGS_MAX_CONCURRENT_STREAMS. Реализации СЛЕДУЕТ также пытаться сохранить состояние для потоков, которые активно используются в дереве приоритетов.

Если он сохранил достаточно состояния, чтобы сделать это, конечной точке, получающей кадр ПРИОРИТЕТА, который изменяет приоритет закрытого потока, СЛЕДУЕТ изменять зависимости потоков, которые зависят от него.

5.3.5. Приоритеты по умолчанию

Всем потокам изначально присваивается неисключительная зависимость от потока 0x0. Выдвигаемые потоки (раздел 8.2) изначально зависят от их связанного потока. В обоих случаях потокам присваивается вес по умолчанию 16.

5.4. Обработка ошибок

HTTP/2 кадрирование допускает два класса ошибок:

  • Состояние ошибки, которое делает все соединение непригодным для использования, является ошибкой соединения.
  • Ошибка в отдельном потоке является ошибкой потока.

Список кодов ошибок включен в Раздел 7.

5.4.1. Обработка ошибок соединения

Ошибка соединения — это любая ошибка, которая препятствует дальнейшей обработке слоя кадра или повреждает любое состояние соединения.

Конечной точке, в которой обнаружена ошибка соединения, СЛЕДУЕТ сначала отправить кадр GOAWAY (раздел 6.8) с идентификатором потока последнего потока, который он успешно получил от своего партнера. Кадр GOAWAY содержит код ошибки, который указывает, почему соединение прерывается. После отправки кадра GOAWAY в случае ошибки конечная точка ДОЛЖНА закрыть соединение TCP.

Возможно, что GOAWAY не будет надежно получен принимающей конечной точкой ([RFC7230 #], раздел 6.6 описывает, как немедленное закрытие соединения может привести к потере данных). В случае ошибки соединения GOAWAY предоставляет только наилучшую попытку связаться с партнером о том, почему разрывается соединение.

Конечная точка может завершить соединение в любое время. В частности, конечная точка МОЖЕТ выбрать обработку ошибки потока как ошибки подключения. Конечные точки ДОЛЖНЫ отправить кадр GOAWAY при завершении соединения, если это позволяют обстоятельства.

5.4.2. Обработка ошибок потока

Ошибка потока — это ошибка, связанная с конкретным потоком, которая не влияет на обработку других потоков.

Конечная точка, которая обнаруживает ошибку потока, отправляет кадр RST_STREAM (раздел 6.4), который содержит идентификатор потока, в котором произошла ошибка. Кадр RST_STREAM включает в себя код ошибки, который указывает тип ошибки.

RST_STREAM — это последний кадр, который конечная точка может отправить в потоке. Узел, который отправляет кадр RST_STREAM, ДОЛЖЕН быть готов принять любые кадры, которые были отправлены или поставлены в очередь для отправки удаленным узлом. Эти кадры можно игнорировать, кроме случаев, когда они изменяют состояние соединения (например, состояние, поддерживаемое для сжатия заголовка (раздел 4.3) или управления потоком).

Обычно конечной точке НЕ СЛЕДУЕТ отправлять более одного кадра RST_STREAM для любого потока. Тем не менее, конечная точка МОЖЕТ отправлять дополнительные кадры RST_STREAM, если она принимает кадры в закрытом потоке по истечении более чем двухстороннего времени. Такое поведение разрешено иметь дело с неправильной реализацией.

Чтобы избежать зацикливания, конечная точка НЕ ДОЛЖНА отправлять RST_STREAM в ответ на кадр RST_STREAM.

5.4.3. Завершение соединения

Если TCP-соединение закрыто или сброшено, в то время как потоки остаются в «открытом» или «полузакрытом» состоянии, то затронутые потоки не могут быть автоматически повторены (подробности см. в разделе 8.1.4).

5.5. Расширение HTTP/2

HTTP/2 разрешает расширение протокола. В рамках ограничений, описанных в этом разделе, расширения протокола могут использоваться для предоставления дополнительных услуг или изменения любого аспекта протокола. Расширения эффективны только в рамках одного соединения HTTP/2.

Это относится к элементам протокола, определенным в этом документе. Это не влияет на существующие параметры расширения HTTP, такие как определение новых методов, кодов состояния или полей заголовка.

Расширениям разрешается использовать новые типы кадров (раздел 4.1), новые настройки (раздел 6.5.2) или новые коды ошибок (раздел 7). Реестры создаются для управления этими точками расширения: типами кадров (раздел 11.2), настройками (раздел 11.3) и кодами ошибок (раздел 11.4).

Реализации ДОЛЖНЫ игнорировать неизвестные или неподдерживаемые значения во всех расширяемых элементах протокола. Реализации ДОЛЖНЫ отбрасывать кадры, которые имеют неизвестные или неподдерживаемые типы. Это означает, что любая из этих точек расширения может безопасно использоваться расширениями без предварительной договоренности или согласования. Однако кадры расширения, которые появляются в середине блока заголовка (раздел 4.3), не допускаются; они ДОЛЖНЫ рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Расширения, которые могут изменить семантику существующих компонентов протокола, ДОЛЖНЫ быть согласованы перед использованием. Например, расширение, которое изменяет расположение кадра HEADERS, не может использоваться, пока узел не дал положительный сигнал, что это приемлемо. В этом случае также может потребоваться согласование, когда пересмотренный макет вступит в силу. Обратите внимание, что обработка любых кадров, отличных от кадров DATA, в качестве потока управления является таким изменением семантики и может быть осуществлена только путем согласования.

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

6. Определения кадров

Эта спецификация определяет количество типов кадров, каждый из которых идентифицируется уникальным 8-битным кодом типа. Каждый тип кадра служит определенной цели при установлении и управлении как соединением в целом, так и отдельными потоками.

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

6.1. DATA

Кадры DATA (тип = 0x0) передают произвольные последовательности октетов переменной длины, связанные с потоком. Один или несколько кадров DATA используются, например, для передачи полезных нагрузок HTTP-запроса или ответа.

Кадры данных могут также содержать отступы. Заполнение может быть добавлено к кадрам DATA, чтобы скрыть размер сообщений. Обивка — это функция безопасности; см. раздел 10.7.

Рисунок 6 - Полезная нагрузка DATA Frame
Рисунок 6 — Полезная нагрузка DATA Frame

Кадр DATA содержит следующие поля:

  • Pad Length (Длина заполнения): 8-битное поле, содержащее длину заполнения кадра в единицах октетов. Это поле является условным (как обозначено на диаграмме символом «?») И присутствует только в том случае, если установлен флаг PADDED.
  • Data (Данные): данные приложения. Объем данных является остатком полезной нагрузки кадра после вычитания длины других присутствующих полей.
  • Padding (Заполнение): октеты заполнения, которые не содержат семантического значения приложения. Октеты заполнения ДОЛЖНЫ быть установлены на ноль при отправке. Получатель не обязан проверять заполнение, но МОЖЕТ рассматривать ненулевое заполнение как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадр DATA определяет следующие флаги:

  • END_STREAM (0x1): при установке бит 0 указывает, что этот кадр является последним, который конечная точка отправит для идентифицированного потока. Установка этого флага приводит к тому, что поток входит в одно из «полузакрытых» состояний или в «закрытое» состояние (раздел 5.1).
  • PADDED (0x8): если установлен, бит 3 указывает, что поле Pad Length и все заполненные поля присутствуют.

Кадры данных ДОЛЖНЫ быть связаны с потоком. Если получен кадр DATA с полем идентификатора потока 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке подключения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадры DATA подлежат управлению потоком и могут отправляться только тогда, когда поток находится в состоянии «открыто» или «полузакрыто (удаленно)». Вся полезная нагрузка фрейма DATA включена в управление потоком, включая поля Pad Length и Padding, если они есть. Если получен кадр DATA, поток которого не находится в состоянии «открыто» или «полузакрыто (локально)», получатель ДОЛЖЕН ответить сообщением об ошибке потока (раздел 5.4.2) типа STREAM_CLOSED.

Общее количество октетов заполнения определяется значением поля Длина поля. Если длина дополнения равна длине полезной нагрузки кадра или больше, получатель ДОЛЖЕН рассматривать это как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Примечание. Размер кадра можно увеличить на один октет, добавив поле длины пэда со значением ноль.

6.2. HEADERS

Кадр HEADERS (тип = 0x1) используется для открытия потока (раздел 5.1) и дополнительно содержит фрагмент блока заголовка. Кадры HEADERS могут отправляться в потоке в состоянии «незанято», «зарезервировано (локально)», «открыто» или «полузакрыто (удаленно)».

Рисунок 7 - Полезная нагрузка кадра заголовков
Рисунок 7 — Полезная нагрузка кадра заголовков

Полезная нагрузка кадра HEADERS имеет следующие поля:

  • Pad Length (Длина заполнения): 8-битное поле, содержащее длину заполнения кадра в единицах октетов. Это поле присутствует, только если установлен флаг PADDED.
  • E: однобитный флаг, указывающий, что зависимость потока является исключительной (см. Раздел 5.3). Это поле присутствует, только если установлен флаг ПРИОРИТЕТ.
  • Stream Dependency (Зависимость потока): 31-битный идентификатор потока для потока, от которого зависит этот поток (см. Раздел 5.3). Это поле присутствует, только если установлен флаг ПРИОРИТЕТ.
  • Weight (Вес): 8-разрядное целое число без знака, представляющее вес приоритета для потока (см. Раздел 5.3). Добавьте единицу к значению, чтобы получить вес от 1 до 256. Это поле присутствует, только если установлен флаг ПРИОРИТЕТ.
  • Header Block Fragment (Фрагмент блока заголовка): Фрагмент блока заголовка (раздел 4.3).
  • Padding (Заполнение): отступы октетов.

Кадр HEADERS определяет следующие флаги:

  • END_STREAM (0x1): если установлено, бит 0 указывает, что блок заголовка (раздел 4.3) является последним, который конечная точка отправит для идентифицированного потока. Кадр HEADERS несет флаг END_STREAM, который сигнализирует об окончании потока. Однако за кадром HEADERS с установленным флагом END_STREAM могут следовать кадры CONTINUATION в том же потоке. Логически, кадры ПРОДОЛЖЕНИЯ являются частью рамки HEADERS.
  • END_HEADERS (0x4): если установлено, бит 2 указывает, что этот кадр содержит весь блок заголовка (раздел 4.3) и за ним не следуют какие-либо кадры ПРОДОЛЖЕНИЯ. НЕОБХОДИМО, чтобы за кадром HEADERS без установленного флага END_HEADERS следовал кадр CONTINUATION для того же потока. Приемник ДОЛЖЕН трактовать получение любого другого типа кадра или кадра в другом потоке как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.
  • PADDED (0x8): если установлен, бит 3 указывает, что поле Pad Length и все заполненные поля присутствуют.
  • PRIORITY (0x20): если установлен, бит 5 указывает на наличие полей «Эксклюзивный флаг» (E), «Зависимость потока» и «Вес»; см. раздел 5.3.

Полезная нагрузка кадра HEADERS содержит фрагмент блока заголовка (раздел 4.3). Блок заголовка, который не помещается в кадр HEADERS, продолжается в кадре ПРОДОЛЖЕНИЕ (раздел 6.10).

Кадры HEADERS ДОЛЖНЫ быть связаны с потоком. Если получен кадр HEADERS, чье поле идентификатора потока равно 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадр HEADERS изменяет состояние соединения, как описано в разделе 4.3.

Рамка HEADERS может включать прокладку. Поля заполнения и флаги идентичны тем, которые определены для кадров DATA (раздел 6.1). Заполнение, которое превышает размер, оставшийся для фрагмента блока заголовка, ДОЛЖНО рассматриваться как PROTOCOL_ERROR.

Информация о приоритезации в кадре HEADERS логически эквивалентна отдельному кадру PRIORITY, но включение в HEADERS позволяет избежать оттока приоритизации потоков при создании новых потоков. Поля приоритизации в кадрах HEADERS, следующих за первыми в потоке, перераспределяют поток (раздел 5.3.3).

6.3. PRIORITY

Фрейм ПРИОРИТЕТА (тип = 0x2) определяет рекомендованный отправителем приоритет потока (раздел 5.3). Он может быть отправлен в любом состоянии потока, включая незанятые или закрытые потоки.

Рисунок 8 Полезная нагрузка кадра PRIORITY
Рисунок 8 Полезная нагрузка кадра PRIORITY

Полезная нагрузка кадра PRIORITY содержит следующие поля:

  • E: однобитный флаг, указывающий, что зависимость потока является исключительной (см. Раздел 5.3).
  • Stream Dependency (Зависимость потока): 31-битный идентификатор потока для потока, от которого зависит этот поток (см. Раздел 5.3).
  • Weight (Вес): 8-разрядное целое число без знака, представляющее вес приоритета для потока (см. Раздел 5.3). Добавьте один к значению, чтобы получить вес от 1 до 256.

Кадр PRIORITY не определяет никаких флагов.

Кадр PRIORITY всегда идентифицирует поток. Если кадр ПРИОРИТЕТА получен с идентификатором потока 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадр PRIORITY может быть отправлен в потоке в любом состоянии, хотя он не может быть отправлен между последовательными кадрами, которые составляют один блок заголовка (Раздел 4.3). Обратите внимание, что этот кадр может прибыть после завершения обработки или отправки кадра, что приведет к тому, что он не окажет влияния на идентифицированный поток. Для потока, который находится в «полузакрытом (удаленном)» или «закрытом» состоянии, этот кадр может влиять только на обработку идентифицированного потока и его зависимых потоков; это не влияет на передачу кадра в этом потоке.

Кадр ПРИОРИТЕТА может быть отправлен для потока в состоянии «незанято» или «закрыто». Это позволяет сделать переориторизацию группы зависимых потоков путем изменения приоритета неиспользованного или закрытого родительского потока.

НЕОБХОДИМО, чтобы кадр ПРИОРИТЕТА с длиной, не превышающей 5 октетов, считался ошибкой потока (раздел 5.4.2) типа FRAME_SIZE_ERROR.

6.4. RST_STREAM

Кадр RST_STREAM (тип = 0x3) допускает немедленное завершение потока. RST_STREAM отправляется для запроса отмены потока или для указания того, что возникла ошибка.

Рисунок 9 Полезная нагрузка кадра RST_STREAM
Рисунок 9 Полезная нагрузка кадра RST_STREAM

Кадр RST_STREAM содержит одно 32-разрядное целое число без знака, идентифицирующее код ошибки (раздел 7). Код ошибки указывает, почему поток прерывается.

Кадр RST_STREAM не определяет никаких флагов.

Кадр RST_STREAM полностью завершает указанный поток и заставляет его переходить в «закрытое» состояние. После получения RST_STREAM в потоке получатель НЕ ДОЛЖЕН отправлять дополнительные кадры для этого потока, за исключением PRIORITY. Однако после отправки RST_STREAM отправляющая конечная точка ДОЛЖНА быть готова принять и обработать дополнительные кадры, отправленные в потоке, которые могли быть отправлены одноранговым узлом до прибытия RST_STREAM.

Кадры RST_STREAM ДОЛЖНЫ быть связаны с потоком. Если кадр RST_STREAM получен с идентификатором потока 0x0, получатель ДОЛЖЕН трактовать это как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадры RST_STREAM НЕ ДОЛЖНЫ отправляться для потока в состоянии «ожидания». Если получен кадр RST_STREAM, идентифицирующий свободный поток, получатель ДОЛЖЕН рассматривать это как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадр RST_STREAM длиной не более 4 октетов ДОЛЖЕН рассматриваться как ошибка соединения (раздел 5.4.1) типа FRAME_SIZE_ERROR.

6.5. SETTINGS

Кадр SETTINGS (тип = 0x4) передает параметры конфигурации, которые влияют на взаимодействие конечных точек, такие как предпочтения и ограничения на поведение одноранговых узлов. Кадр SETTINGS также используется для подтверждения получения этих параметров. По отдельности параметр SETTINGS может также называться «настройкой».

Параметры SETTINGS не согласовываются; они описывают характеристики отправляющего узла, которые используются принимающим узлом. Различные значения для одного и того же параметра могут быть объявлены каждым узлом. Например, клиент может установить высокое начальное окно управления потоком, тогда как сервер может установить более низкое значение для экономии ресурсов.

Кадр SETTINGS ДОЛЖЕН быть отправлен обеими конечными точками в начале соединения, и МОЖЕТ быть отправлен в любое другое время любой конечной точкой в течение всего времени существования соединения. Реализации ДОЛЖНЫ поддерживать все параметры, определенные в этой спецификации.

Каждый параметр в кадре SETTINGS заменяет любое существующее значение для этого параметра. Параметры обрабатываются в том порядке, в котором они появляются, и получателю кадра SETTINGS не нужно поддерживать какое-либо состояние, кроме текущего значения его параметров. Следовательно, значение параметра SETTINGS является последним значением, которое видит получатель.

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

  • ACK (0x1): если установлено, бит 0 указывает, что этот кадр подтверждает получение и применение кадра SETTINGS партнера. Когда этот бит установлен, полезная нагрузка кадра SETTINGS ДОЛЖНА быть пустой. Получение кадра SETTINGS с установленным флагом ACK и значением поля длины, отличным от 0, ДОЛЖНО рассматриваться как ошибка соединения (раздел 5.4.1) типа FRAME_SIZE_ERROR. Для получения дополнительной информации см. Раздел 6.5.3 («Синхронизация настроек»).

Кадры SETTINGS всегда применяются к соединению, а не к одному потоку. Идентификатор потока для кадра SETTINGS ДОЛЖЕН быть нулевым (0x0). Если конечная точка получает кадр SETTINGS, чье поле идентификатора потока отличается от 0x0, конечная точка ДОЛЖНА ответить ошибкой соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Рамка SETTINGS влияет на состояние соединения. НЕПРАВИЛЬНО сформированный или неполный кадр SETTINGS ДОЛЖЕН рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Кадр SETTINGS с длиной, не кратной 6 октетам, ДОЛЖЕН рассматриваться как ошибка соединения (раздел 5.4.1) типа FRAME_SIZE_ERROR.

6.5.1. Формат SETTINGS

Полезная нагрузка кадра SETTINGS состоит из нуля или более параметров, каждый из которых состоит из 16-разрядного идентификатора установки без знака и 32-разрядного значения без знака.

Рисунок 10 - Настройка формата
Рисунок 10 — Настройка формата

6.5.2. Определенные параметры SETTINGS

Определены следующие параметры:

SETTINGS_HEADER_TABLE_SIZE (0x1)

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

SETTINGS_ENABLE_PUSH (0x2)

Этот параметр можно использовать для отключения принудительной отправки сервером (раздел 8.2). Конечная точка НЕ ДОЛЖНА отправлять кадр PUSH_PROMISE, если она получает этот параметр, установленный в значение 0. Конечная точка, которая установила для этого параметра значение 0 и получила подтверждение, ДОЛЖНА трактовать получение кадра PUSH_PROMISE как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Начальное значение равно 1, что означает, что отправка сервером разрешена. Любое значение, отличное от 0 или 1, ДОЛЖНО рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

SETTINGS_MAX_CONCURRENT_STREAMS (0x3)

Указывает максимальное количество одновременных потоков, которое разрешит отправитель. Этот предел является направленным: он применяется к количеству потоков, которые отправитель разрешает получателю создавать. Первоначально нет предела этому значению. Рекомендуется, чтобы это значение было не меньше 100, чтобы не излишне ограничивать параллелизм.

Значение 0 для SETTINGS_MAX_CONCURRENT_STREAMS НЕ ДОЛЖНО рассматриваться конечными точками как особые. Нулевое значение не позволяет создавать новые потоки; однако это также может произойти для любого предела, который исчерпан активными потоками. Серверы ДОЛЖНЫ устанавливать нулевое значение только на короткие промежутки времени; если сервер не желает принимать запросы, закрытие соединения является более подходящим.

SETTINGS_INITIAL_WINDOW_SIZE (0x4)

Указывает начальный размер окна отправителя (в октетах) для управления потоком на уровне потока. Начальное значение составляет 2 ^ 16-1 (65 535) октетов.

Этот параметр влияет на размер окна всех потоков (см. Раздел 6.9.2).

Значения выше максимального размера окна управления потоком, равного 2 ^ 31-1, ДОЛЖНЫ рассматриваться как ошибка соединения (раздел 5.4.1) типа FLOW_CONTROL_ERROR.

SETTINGS_MAX_FRAME_SIZE (0x5)

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

Начальное значение составляет 2 ^ 14 (16 384) октетов. Значение, объявленное конечной точкой, ДОЛЖНО быть между этим начальным значением и максимально допустимым размером кадра (2 ^ 24-1 или 16 777 215 октетов) включительно. Значения за пределами этого диапазона ДОЛЖНЫ рассматриваться как ошибка соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

SETTINGS_MAX_HEADER_LIST_SIZE (0x6)

Этот консультативный параметр информирует одноранговый узел о максимальном размере списка заголовков, который отправитель готов принять в октетах. Значение основано на несжатом размере полей заголовка, включая длину имени и значения в октетах, плюс накладные расходы в 32 октета для каждого поля заголовка.

Для любого данного запроса МОЖЕТ быть применен более низкий предел, чем рекламируемый. Начальное значение этого параметра не ограничено.

 

Конечная точка, которая получает кадр SETTINGS с любым неизвестным или неподдерживаемым идентификатором, ДОЛЖНА игнорировать этот параметр.

6.5.3. Синхронизация SETTINGS

Большинство значений в SETTINGS выигрывают или требуют понимания того, когда одноранговый узел получил и применил измененные значения параметров. Чтобы обеспечить такие моменты времени синхронизации, получатель кадра SETTINGS, в котором не установлен флаг ACK, ДОЛЖЕН применить обновленные параметры как можно скорее после получения.

Значения в кадре SETTINGS ДОЛЖНЫ быть обработаны в том порядке, в котором они появляются, без обработки другого кадра между значениями. Неподдерживаемые параметры ДОЛЖНЫ игнорироваться. Как только все значения обработаны, получатель ДОЛЖЕН немедленно выдать кадр SETTINGS с установленным флагом ACK. После получения кадра SETTINGS с установленным флагом ACK отправитель измененных параметров может рассчитывать на примененную настройку.

Если отправитель кадра SETTINGS не получает подтверждение в течение разумного периода времени, он МОЖЕТ выдать ошибку соединения (Раздел 5.4.1) типа SETTINGS_TIMEOUT.

6.6. PUSH_PROMISE

Кадр PUSH_PROMISE (тип = 0x5) используется для уведомления конечной точки однорангового узла заранее о потоках, которые отправитель намеревается инициировать. Кадр PUSH_PROMISE включает в себя 31-битный идентификатор без знака потока, который конечная точка планирует создать вместе с набором заголовков, которые обеспечивают дополнительный контекст для потока. Раздел 8.2 содержит подробное описание использования кадров PUSH_PROMISE.

Рисунок 11 - Формат полезной нагрузки PUSH_PROMISE
Рисунок 11 — Формат полезной нагрузки PUSH_PROMISE

Полезная нагрузка кадра PUSH_PROMISE имеет следующие поля:

  • Pad Length (Длина заполнения): 8-битное поле, содержащее длину заполнения кадра в единицах октетов. Это поле присутствует, только если установлен флаг PADDED.
  • R: один зарезервированный бит.
  • Promised Stream ID (Обещанный идентификатор потока): 31-разрядное целое число без знака, которое идентифицирует поток, зарезервированный функцией PUSH_PROMISE. Обещанный идентификатор потока ДОЛЖЕН быть допустимым выбором для следующего потока, отправленного отправителем (см. «Идентификатор нового потока» в Разделе 5.1.1).
  • Header Block Fragment (Фрагмент блока заголовка): Фрагмент блока заголовка (раздел 4.3), содержащий поля заголовка запроса.
  • Padding (Заполнение): отступы октетов.

Кадр PUSH_PROMISE определяет следующие флаги:

  • END_HEADERS (0x4): если установлено, бит 2 указывает, что этот кадр содержит весь блок заголовка (раздел 4.3) и за ним не следуют какие-либо кадры ПРОДОЛЖЕНИЯ.
    За кадром PUSH_PROMISE без установленного флага END_HEADERS ДОЛЖЕН следовать кадр CONTINUATION для того же потока. Приемник ДОЛЖЕН трактовать получение любого другого типа кадра или кадра в другом потоке как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.
  • PADDED (0x8): если установлен, бит 3 указывает, что поле Pad Length и все заполненные поля присутствуют.

Кадры PUSH_PROMISE ДОЛЖНЫ отправляться только в инициируемом одноранговой связью потоке, который находится либо в «открытом», либо «полузакрытом (удаленном)» состоянии. Идентификатор потока кадра PUSH_PROMISE указывает поток, с которым он связан. Если в поле идентификатора потока указано значение 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Обещанные потоки не обязательно должны использоваться в том порядке, в котором они обещаны. PUSH_PROMISE резервирует только идентификаторы потока для последующего использования.

PUSH_PROMISE НЕ ДОЛЖЕН отправляться, если для параметра SETTINGS_ENABLE_PUSH конечной точки однорангового узла установлено значение 0. Конечная точка, которая установила этот параметр и получила подтверждение, ДОЛЖНА трактовать получение кадра PUSH_PROMISE как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Получатели кадров PUSH_PROMISE могут отклонить обещанные потоки, возвращая RST_STREAM со ссылкой на идентификатор обещанного потока обратно отправителю PUSH_PROMISE.

Кадр PUSH_PROMISE изменяет состояние соединения двумя способами. Во-первых, включение блока заголовка (раздел 4.3) потенциально изменяет состояние, поддерживаемое для сжатия заголовка. Во-вторых, PUSH_PROMISE также резервирует поток для последующего использования, в результате чего обещанный поток переходит в «зарезервированное» состояние. Отправитель НЕ ДОЛЖЕН отправлять PUSH_PROMISE в потоке, если этот поток не является «открытым» или «полузакрытым (удаленным)»; отправитель ДОЛЖЕН гарантировать, что обещанный поток является допустимым выбором для нового идентификатора потока (раздел 5.1.1) (то есть обещанный поток ДОЛЖЕН находиться в состоянии «ожидания»).

Поскольку PUSH_PROMISE резервирует поток, игнорирование кадра PUSH_PROMISE приводит к тому, что состояние потока становится неопределенным. Приемник ДОЛЖЕН трактовать получение PUSH_PROMISE в потоке, который не является ни «открытым», ни «полузакрытым (локальным)», как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR. Однако конечная точка, которая отправила RST_STREAM в связанном потоке, ДОЛЖНА обрабатывать кадры PUSH_PROMISE, которые могли быть созданы до получения и обработки кадра RST_STREAM.

Получатель ДОЛЖЕН трактовать получение PUSH_PROMISE, который обещает неверный идентификатор потока (раздел 5.1.1), как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR. Обратите внимание, что недопустимый идентификатор потока является идентификатором для потока, который в данный момент не находится в состоянии «ожидания».

Кадр PUSH_PROMISE может включать заполнение. Поля заполнения и флаги идентичны тем, которые определены для кадров DATA (раздел 6.1).

6.7. PING

Кадр PING (тип = 0x6) представляет собой механизм для измерения минимального времени прохождения сигнала в обоих направлениях от отправителя, а также для определения, все еще функционирует ли незанятое соединение. Кадры PING могут быть отправлены с любой конечной точки.

Рисунок 12 - Формат полезной нагрузки PING
Рисунок 12 — Формат полезной нагрузки PING

В дополнение к заголовку кадра кадры PING ДОЛЖНЫ содержать 8 октетов непрозрачных данных в полезной нагрузке. Отправитель может включить любое значение, которое он выберет, и использовать эти октеты любым способом.

Приемники кадра PING, который не включает флаг ACK, ДОЛЖНЫ послать кадр PING с флагом ACK, установленным в ответ, с идентичной полезной нагрузкой. Ответы PING ДОЛЖНЫ иметь более высокий приоритет, чем любой другой кадр.

Кадр PING определяет следующие флаги:

  • ACK (0x1): если установлено, бит 0 указывает, что этот кадр PING является ответом PING. Конечная точка ДОЛЖНА установить этот флаг в ответах PING. Конечная точка НЕ ДОЛЖНА отвечать на кадры PING, содержащие этот флаг.

Кадры PING не связаны с каким-либо отдельным потоком. Если кадр PING получен со значением поля идентификатора потока, отличным от 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Получение кадра PING со значением поля длины, отличным от 8, ДОЛЖНО рассматриваться как ошибка соединения (раздел 5.4.1) типа FRAME_SIZE_ERROR.

6.8. GOAWAY

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

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

После отправки отправитель будет игнорировать кадры, отправленные в потоках, инициированных получателем, если поток имеет идентификатор выше, чем включенный последний идентификатор потока. Приемники кадра GOAWAY НЕ ДОЛЖНЫ открывать дополнительные потоки в соединении, хотя для новых потоков может быть установлено новое соединение.

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

Конечные точки ДОЛЖНЫ всегда отправлять кадр GOAWAY перед закрытием соединения, чтобы удаленный узел мог знать, был ли поток частично обработан или нет. Например, если HTTP-клиент отправляет POST в то же время, когда сервер закрывает соединение, клиент не может знать, начал ли сервер обрабатывать этот POST-запрос, если сервер не отправляет кадр GOAWAY, чтобы указать, какие потоки он может иметь действовал на.

Конечная точка может предпочесть закрыть соединение, не отправляя GOAWAY для неправильно работающих пиров.

Кадр GOAWAY не может непосредственно предшествовать закрытию соединения; получатель GOAWAY, который больше не использует соединение, ДОЛЖЕН по-прежнему отправлять кадр GOAWAY до завершения соединения.

Рисунок 13 - Формат полезной нагрузки GOAWAY
Рисунок 13 — Формат полезной нагрузки GOAWAY

Кадр GOAWAY не определяет никаких флагов.

Кадр GOAWAY применяется к соединению, а не к конкретному потоку. Конечная точка ДОЛЖНА обрабатывать кадр GOAWAY с идентификатором потока, отличным от 0x0, как ошибку соединения (Раздел 5.4.1) типа PROTOCOL_ERROR.

Последний идентификатор потока в кадре GOAWAY содержит идентификатор потока с наибольшим номером, для которого отправитель кадра GOAWAY, возможно, предпринял какое-то действие или мог бы еще принять меры. Все потоки вплоть до идентифицированного потока, возможно, были обработаны каким-либо образом. Последний идентификатор потока может быть установлен в 0, если потоки не были обработаны.

Примечание. В этом контексте «обработанный» означает, что некоторые данные из потока были переданы в какой-либо программный уровень более высокого уровня, который в результате мог предпринять некоторые действия.

Если соединение завершается без кадра GOAWAY, последний идентификатор потока фактически является максимально возможным идентификатором потока.

В потоках с идентификаторами с меньшими или равными номерами, которые не были закрыты полностью до закрытия соединения, повторная попытка запросов, транзакций или любых действий протокола невозможна, за исключением идемпотентных действий, таких как HTTP GET, PUT или DELETE. Любая активность протокола, использующая потоки с более высоким номером, может быть безопасно повторена с использованием нового соединения.

Активность в потоках, пронумерованных ниже или равных последнему идентификатору потока, может все еще успешно завершиться. Отправитель кадра GOAWAY может корректно завершить соединение, отправив кадр GOAWAY, поддерживая соединение в «открытом» состоянии, пока не завершатся все входящие потоки.

Конечная точка МОЖЕТ отправлять несколько кадров GOAWAY, если обстоятельства меняются. Например, конечная точка, которая отправляет GOAWAY с NO_ERROR во время постепенного отключения, может впоследствии столкнуться с условием, которое требует немедленного прекращения соединения. Последний идентификатор потока из последнего принятого кадра GOAWAY указывает, на какие потоки можно было воздействовать. Конечные точки НЕ ДОЛЖНЫ увеличивать значение, которое они отправляют в последнем идентификаторе потока, поскольку одноранговые узлы уже могли повторить необработанные запросы на другом соединении.

Клиент, который не может повторить запросы, теряет все запросы, находящиеся в полете, когда сервер закрывает соединение. Это особенно верно для посредников, которые могут не обслуживать клиентов, использующих HTTP/2. Сервер, который пытается корректно завершить соединение, ДОЛЖЕН послать начальный кадр GOAWAY с последним идентификатором потока, установленным на 2 ^ 31-1, и кодом NO_ERROR. Это сигнализирует клиенту, что завершение работы неизбежно и что дальнейшие запросы запрещены. После предоставления времени для создания любого потока в полете (по меньшей мере, одного времени прохождения туда-обратно) сервер может отправить еще один кадр GOAWAY с обновленным идентификатором последнего потока. Это гарантирует, что соединение может быть чисто отключено без потери запросов.

После отправки кадра GOAWAY отправитель может отбросить кадры для потоков, инициированных получателем, с идентификаторами, превышающими идентифицированный последний поток. Однако любые кадры, которые изменяют состояние соединения, не могут быть полностью проигнорированы. Например, кадры HEADERS, PUSH_PROMISE и CONTINUATION ДОЛЖНЫ быть минимально обработаны, чтобы обеспечить согласованность состояния, поддерживаемого для сжатия заголовка (см. Раздел 4.3); аналогично, кадры DATA ДОЛЖНЫ учитываться в окне управления потоком соединений. Невозможность обработать эти кадры может привести к тому, что управление потоком или состояние сжатия заголовка станут несинхронизированными.

Кадр GOAWAY также содержит 32-битный код ошибки (раздел 7), который содержит причину закрытия соединения.

Конечные точки МОГУТ добавлять непрозрачные данные в полезную нагрузку любого кадра GOAWAY. Дополнительные данные отладки предназначены только для диагностических целей и не несут смысловой ценности. Отладочная информация может содержать данные безопасности или конфиденциальные данные. НЕОБХОДИМО, чтобы зарегистрированные или иным образом сохраненные отладочные данные ДОЛЖНЫ иметь адекватные меры безопасности для предотвращения несанкционированного доступа.

6.9. WINDOW_UPDATE

Кадр WINDOW_UPDATE (тип = 0x8) используется для реализации управления потоком; см. раздел 5.2 для обзора.

Управление потоком работает на двух уровнях: для каждого отдельного потока и для всего соединения.

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

Управление потоком применяется только к кадрам, которые определены как подлежащие управлению потоком. Из типов фреймов, определенных в этом документе, это включает только фреймы DATA. НЕОБХОДИМО, чтобы кадры, которые освобождены от управления потоком, принимались и обрабатывались, если только получатель не может назначить ресурсы для обработки кадра. Приемник МОЖЕТ ответить ошибкой потока (раздел 5.4.2) или ошибкой соединения (раздел 5.4.1) типа FLOW_CONTROL_ERROR, если он не может принять кадр.

Рисунок 14 - Формат полезной нагрузки WINDOW_UPDATE
Рисунок 14 — Формат полезной нагрузки WINDOW_UPDATE

Полезная нагрузка кадра WINDOW_UPDATE представляет собой один зарезервированный бит плюс 31-разрядное целое число без знака, указывающее количество октетов, которые отправитель может передать в дополнение к существующему окну управления потоком. Допустимый диапазон приращения к окну управления потоком — от 1 до 2 ^ 31-1 (2 147 483 647) октетов.

Кадр WINDOW_UPDATE не определяет никаких флагов.

Кадр WINDOW_UPDATE может быть специфичным для потока или всего соединения. В первом случае идентификатор потока кадра указывает на затронутый поток; в последнем случае значение «0» указывает, что все соединение является субъектом кадра.

Приемник ДОЛЖЕН обрабатывать получение кадра WINDOW_UPDATE с шагом окна управления потоком 0 как ошибку потока (раздел 5.4.2) типа PROTOCOL_ERROR; ошибки в окне управления потоком соединений ДОЛЖНЫ рассматриваться как ошибка соединения (раздел 5.4.1).

WINDOW_UPDATE может быть отправлено одноранговым узлом, который отправил кадр с флагом END_STREAM. Это означает, что получатель может получить кадр WINDOW_UPDATE в «полузакрытом (удаленном)» или «закрытом» потоке. Получатель НЕ ДОЛЖЕН трактовать это как ошибку (см. Раздел 5.1).

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

Кадр WINDOW_UPDATE длиной не более 4 октетов ДОЛЖЕН рассматриваться как ошибка соединения (раздел 5.4.1) типа FRAME_SIZE_ERROR.

6.9.1. Окно Flow-Control

Управление потоком в HTTP/2 реализовано с использованием окна, сохраняемого каждым отправителем в каждом потоке. Окно управления потоком данных представляет собой простое целочисленное значение, которое указывает, сколько октетов данных отправителю разрешено передавать; как таковой, его размер является мерой буферной емкости приемника.

Применимо два окна управления потоком: окно управления потоком потока и окно управления потоком соединения. Отправитель НЕ ДОЛЖЕН отправлять кадр с управлением потоком, длина которого превышает пространство, доступное в любом из окон управления потоком, объявленных получателем. Кадры с нулевой длиной с установленным флагом END_STREAM (то есть пустой кадр DATA) МОГУТ быть отправлены, если в любом из окон управления потоком нет свободного места.

Для расчетов управления потоком 9-октетный заголовок кадра не учитывается.

После отправки кадра с управлением потоком отправитель уменьшает пространство, доступное в обоих окнах, на длину передаваемого кадра.

Получатель кадра отправляет кадр WINDOW_UPDATE, поскольку он потребляет данные и освобождает пространство в окнах управления потоком. Отдельные кадры WINDOW_UPDATE отправляются для окон управления потоком и уровня соединения.

Отправитель, который получает кадр WINDOW_UPDATE, обновляет соответствующее окно на сумму, указанную в кадре.

Отправитель НЕ ДОЛЖЕН допускать, чтобы окно управления потоком превышало 2 ^ 31-1 октета. Если отправитель получает WINDOW_UPDATE, который заставляет окно управления потоком превышать этот максимум, он ДОЛЖЕН завершить поток или соединение, в зависимости от ситуации. Для потоков отправитель отправляет RST_STREAM с кодом ошибки FLOW_CONTROL_ERROR; для соединения отправляется кадр GOAWAY с кодом ошибки FLOW_CONTROL_ERROR.

Кадры с управлением потоком от отправителя и кадры WINDOW_UPDATE от получателя являются полностью асинхронными по отношению друг к другу. Это свойство позволяет получателю активно обновлять размер окна, сохраняемый отправителем, чтобы предотвратить остановку потоков.

6.9.2. Начальный размер окна управления потоком

Когда соединение HTTP/2 устанавливается впервые, создаются новые потоки с начальным размером окна управления потоком 65 535 октетов. Окно контроля потока соединения также составляет 65 535 октетов. Обе конечные точки могут регулировать начальный размер окна для новых потоков, включая значение SETTINGS_INITIAL_WINDOW_SIZE в кадре SETTINGS, который является частью предисловия к соединению. Окно управления потоком соединений может быть изменено только с использованием кадров WINDOW_UPDATE.

До получения кадра SETTINGS, который устанавливает значение для SETTINGS_INITIAL_WINDOW_SIZE, конечная точка может использовать исходный размер окна по умолчанию только при отправке управляемых потоком кадров. Аналогично, в окне управления потоком соединений устанавливается начальный размер окна по умолчанию, пока не будет получен кадр WINDOW_UPDATE.

В дополнение к изменению окна управления потоком для потоков, которые еще не активны, кадр SETTINGS может изменить начальный размер окна управления потоком для потоков с активными окнами управления потоком (то есть потоков в «открытом» или «половинном» закрытое (удаленное) состояние). Когда значение SETTINGS_INITIAL_WINDOW_SIZE изменяется, получатель ДОЛЖЕН отрегулировать размер всех окон управления потоком потока, которые он поддерживает, с помощью разницы между новым значением и старым значением.

Изменение SETTINGS_INITIAL_WINDOW_SIZE может привести к тому, что доступное пространство в окне управления потоком станет отрицательным. Отправитель ДОЛЖЕН отслеживать отрицательное окно управления потоком и НЕ ДОЛЖЕН отправлять новые кадры, контролируемые потоком, пока не получит кадры WINDOW_UPDATE, которые приводят к тому, что окно управления потоком становится положительным.

Например, если клиент немедленно отправляет 60 КБ при установлении соединения, и сервер устанавливает начальный размер окна равным 16 КБ, клиент получит пересчет доступного окна управления потоком на -44 КБ после получения кадра SETTINGS. Клиент сохраняет отрицательное окно управления потоком до тех пор, пока кадры WINDOW_UPDATE не восстановят окно в положительное, после чего клиент может возобновить отправку.

Кадр SETTINGS не может изменить окно управления потоком соединений.

Конечная точка ДОЛЖНА обрабатывать изменение SETTINGS_INITIAL_WINDOW_SIZE, которое приводит к тому, что любое окно управления потоком превышает максимальный размер, как ошибку соединения (Раздел 5.4.1) типа FLOW_CONTROL_ERROR.

6.9.3. Уменьшение размера окна потока

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

После отправки кадра SETTINGS, который уменьшает начальный размер окна управления потоком, приемник МОЖЕТ продолжать обрабатывать потоки, которые превышают пределы управления потоком. Разрешение продолжения потоков не позволяет получателю немедленно уменьшить пространство, которое он резервирует для окон управления потоком. Ход этих потоков также может зависнуть, поскольку для возобновления отправки отправителю необходимы кадры WINDOW_UPDATE. Вместо этого получатель МОЖЕТ отправить RST_STREAM с кодом ошибки FLOW_CONTROL_ERROR для затронутых потоков.

6.10. CONTINUATION

Кадр ПРОДОЛЖЕНИЕ (тип = 0x9) используется для продолжения последовательности фрагментов блока заголовка (раздел 4.3). Можно отправить любое количество кадров CONTINUATION, если предыдущий кадр находится в том же потоке и является кадром HEADERS, PUSH_PROMISE или CONTINUATION без установленного флага END_HEADERS.

Рисунок 15 - Полезная нагрузка кадра CONTINUATION
Рисунок 15 — Полезная нагрузка кадра CONTINUATION

Полезная нагрузка кадра CONTINUATION содержит фрагмент блока заголовка (раздел 4.3).

Фрейм ПРОДОЛЖЕНИЕ определяет следующий флаг:

  • END_HEADERS (0x4): если установлен, бит 2 указывает, что этот кадр заканчивает блок заголовка (раздел 4.3). Если бит END_HEADERS не установлен, за этим кадром ДОЛЖЕН следовать другой кадр ПРОДОЛЖЕНИЯ. Приемник ДОЛЖЕН трактовать получение любого другого типа кадра или кадра в другом потоке как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Фрейм CONTINUATION изменяет состояние соединения, как определено в разделе 4.3.

НЕПРЕРЫВНЫЕ кадры ДОЛЖНЫ быть связаны с потоком. Если получен кадр CONTINUATION, поле идентификатора потока которого равно 0x0, получатель ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

Фрейму CONTINUATION ДОЛЖЕН предшествовать кадр HEADERS, PUSH_PROMISE или CONTINUATION без установленного флага END_HEADERS. Получатель, который наблюдает за нарушением этого правила, ДОЛЖЕН ответить сообщением об ошибке соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

7. Коды ошибок

Коды ошибок — это 32-битные поля, которые используются в кадрах RST_STREAM и GOAWAY для передачи причин потока или ошибки соединения.

Коды ошибок имеют общее кодовое пространство. Некоторые коды ошибок применяются только к потокам или ко всему соединению и не имеют определенной семантики в другом контексте.

Определены следующие коды ошибок:

  • NO_ERROR (0x0): связанное условие не является результатом ошибки. Например, GOAWAY может включать этот код, чтобы указать на постепенное отключение соединения.
  • PROTOCOL_ERROR (0x1): конечная точка обнаружила неспецифическую ошибку протокола. Эта ошибка предназначена для использования, когда более точный код ошибки недоступен.
  • INTERNAL_ERROR (0x2): конечная точка обнаружила непредвиденную внутреннюю ошибку.
  • FLOW_CONTROL_ERROR (0x3): конечная точка обнаружила, что ее узел нарушил протокол управления потоком.
  • SETTINGS_TIMEOUT (0x4): конечная точка отправила кадр SETTINGS, но не получила ответ своевременно. См. Раздел 6.5.3 («Синхронизация настроек»).
  • STREAM_CLOSED (0x5): конечная точка получила кадр после того, как поток был наполовину закрыт.
  • FRAME_SIZE_ERROR (0x6): конечная точка получила кадр с недопустимым размером.
  • REFUSED_STREAM (0x7): конечная точка отклонила поток до выполнения какой-либо обработки приложения (подробности см. В разделе 8.1.4).
  • CANCEL (0x8): используется конечной точкой, чтобы указать, что поток больше не нужен.
  • COMPRESSION_ERROR (0x9): конечная точка не может поддерживать контекст сжатия заголовка для соединения.
  • CONNECT_ERROR (0xa): Соединение, установленное в ответ на запрос CONNECT (раздел 8.3), было сброшено или ненормально закрыто.
  • ENHANCE_YOUR_CALM (0xb): конечная точка обнаружила, что ее одноранговый узел демонстрирует поведение, которое может вызывать чрезмерную нагрузку.
  • INADEQUATE_SECURITY (0xc): базовый транспорт имеет свойства, которые не соответствуют минимальным требованиям безопасности (см. Раздел 9.2).
  • HTTP_1_1_REQUIRED (0xd): конечная точка требует использования HTTP/1.1 вместо HTTP/2.

Неизвестные или неподдерживаемые коды ошибок НЕ ДОЛЖНЫ вызывать какое-либо особое поведение. Они МОГУТ трактоваться реализацией как эквивалентные INTERNAL_ERROR.

8. Обмен сообщениями HTTP

HTTP/2 призван быть максимально совместимым с текущими видами использования HTTP. Это означает, что с точки зрения приложения возможности протокола в основном не изменились. Для этого вся семантика запросов и ответов сохраняется, хотя синтаксис передачи этой семантики изменился.

Таким образом, спецификация и требования семантики и контента HTTP/1.1 [RFC7231 #], условных запросов [RFC7232 #], запросов диапазона [RFC7233 #], кэширования [RFC7234 #] и аутентификации [RFC7235 #] применимы к HTTP/2. Отдельные части синтаксиса и маршрутизации сообщений HTTP/1.1 [RFC7230 #], такие как схемы URI HTTP и HTTPS, также применимы в HTTP/2, но выражение этой семантики для этого протокола определено в следующих разделах.

8.1. Обмен HTTP-запросами / ответами

Клиент отправляет HTTP-запрос на новый поток, используя ранее не использованный идентификатор потока (раздел 5.1.1). Сервер отправляет ответ HTTP в том же потоке, что и запрос.

HTTP-сообщение (запрос или ответ) состоит из:

  1. только для ответа: ноль или более кадров HEADERS (за которыми следуют ноль или более кадров CONTINUATION), содержащих заголовки сообщений информационных (1xx) HTTP-ответов (см. [RFC7230 #], раздел 3.2 и [RFC7231 #], раздел 6.2)
  2. один кадр HEADERS (за которым следует ноль или более кадров CONTINUATION), содержащий заголовки сообщений (см. [RFC7230 #], раздел 3.2)
  3. ноль или более кадров DATA, содержащих тело полезной нагрузки (см. [RFC7230 #], раздел 3.3)
  4. необязательно, один кадр HEADERS, за которым следует ноль или более кадров CONTINUATION, содержащих деталь трейлера, если таковая имеется (см. [RFC7230 #], раздел 4.1.2).

Последний кадр в последовательности имеет флаг END_STREAM, отмечая, что за кадром HEADERS, несущим флаг END_STREAM, могут следовать кадры CONTINUATION, которые переносят любые оставшиеся части блока заголовка.

Другие кадры (из любого потока) НЕ ДОЛЖНЫ появляться между кадром HEADERS и любыми кадрами ПРОДОЛЖЕНИЯ, которые могут последовать.

HTTP/2 использует кадры DATA для переноса полезных данных сообщения. Кодированное передающее кодирование, определенное в Разделе 4.1 [RFC7230 #], НЕ ДОЛЖНО использоваться в HTTP/2.

Конечные поля заголовка переносятся в блоке заголовка, который также завершает поток. Такой блок заголовка представляет собой последовательность, начинающуюся с кадра HEADERS, за которым следует ноль или более кадров CONTINUATION, где кадр HEADERS несет флаг END_STREAM. Блоки заголовка после первого, которые не завершают поток, не являются частью HTTP-запроса или ответа.

Кадр HEADERS (и связанные с ним кадры CONTINUATION) могут появляться только в начале или конце потока. Конечная точка, которая получает кадр HEADERS без установленного флага END_STREAM после получения окончательного (неинформационного) кода состояния, ДОЛЖНА трактовать соответствующий запрос или ответ как неправильно сформированный (Раздел 8.1.2.6).

Обмен запросами и ответами HTTP полностью использует один поток. Запрос начинается с фрейма HEADERS, который переводит поток в открытое состояние. Запрос заканчивается рамкой, содержащей END_STREAM, в результате чего поток становится «полузакрытым (локальным)» для клиента и «полузакрытым (удаленным)» для сервера. Ответ начинается с фрейма HEADERS и заканчивается фреймом END_STREAM, который переводит поток в «закрытое» состояние.

HTTP-ответ завершается после того, как сервер отправляет — или клиент получает — кадр с установленным флагом END_STREAM (включая все кадры CONTINUATION, необходимые для завершения блока заголовка). Сервер может отправить полный ответ до того, как клиент отправит полный запрос, если ответ не зависит от какой-либо части запроса, которая не была отправлена ​​и получена. Когда это так, сервер МОЖЕТ запросить, чтобы клиент прервал передачу запроса без ошибок, отправив RST_STREAM с кодом ошибки NO_ERROR после отправки полного ответа (то есть кадра с флагом END_STREAM).

Клиенты НЕ ДОЛЖНЫ отбрасывать ответы в результате получения RST_STREAM, хотя клиенты всегда могут отказаться от ответов по своему усмотрению по другим причинам.

8.1.1. Обновление с HTTP/2

HTTP/2 удаляет поддержку информационного кода состояния 101 (коммутационные протоколы) ([RFC7231 #], раздел 6.2.2).

Семантика 101 (протоколы коммутации) не применима к мультиплексированному протоколу. Альтернативные протоколы могут использовать те же механизмы, которые HTTP/2 использует для согласования их использования (см. Раздел 3).

8.1.2. Поля заголовка HTTP

Поля заголовка HTTP несут информацию в виде последовательности пар ключ-значение. Список зарегистрированных заголовков HTTP см. В реестре «Поле заголовка сообщения», который находится по адресу <https://www.iana.org/assignments/message-headers>.

Как и в HTTP / 1.x, имена полей заголовков представляют собой строки символов ASCII, которые сравниваются без учета регистра. Однако имена полей заголовка ДОЛЖНЫ быть преобразованы в строчные буквы до их кодирования в HTTP/2. Запрос или ответ, содержащие имена полей заголовка верхнего регистра, ДОЛЖНЫ рассматриваться как некорректные (раздел 8.1.2.6).

8.1.2.1. Поля псевдо-заголовка

В то время как HTTP/1.x использовал начальную строку сообщения (см. [RFC7230 #], раздел 3.1) для передачи целевого URI, метода запроса и кода состояния для ответа, HTTP/2 использует специальные поля псевдо-заголовка для этого начинается символ ‘:’ (ASCII 0x3a).

Поля псевдо-заголовка не являются полями заголовка HTTP. Конечные точки НЕ ДОЛЖНЫ генерировать поля псевдозаголовка, отличные от определенных в этом документе.

Поля псевдо-заголовка действительны только в том контексте, в котором они определены. Поля псевдозаголовка, определенные для запросов, НЕ ДОЛЖНЫ появляться в ответах; Поля псевдо-заголовка, определенные для ответов, НЕ ДОЛЖНЫ появляться в запросах. Поля псевдо-заголовка НЕ ​​ДОЛЖНЫ появляться в трейлерах. Конечные точки ДОЛЖНЫ обрабатывать запрос или ответ, который содержит неопределенные или недействительные поля псевдозаголовка, как неправильно сформированные (раздел 8.1.2.6).

Все поля псевдозаголовка ДОЛЖНЫ появляться в блоке заголовка перед обычными полями заголовка. Любой запрос или ответ, который содержит поле псевдозаголовка, которое появляется в блоке заголовка после поля обычного заголовка, ДОЛЖЕН рассматриваться как некорректный (Раздел 8.1.2.6).

8.1.2.2. Поля заголовка для конкретного соединения

HTTP/2 не использует поле заголовка соединения для указания полей заголовка для конкретного соединения; в этом протоколе метаданные для конкретного соединения передаются другими способами. Конечная точка НЕ ​​ДОЛЖНА генерировать сообщение HTTP/2, содержащее поля заголовка для конкретного соединения; любое сообщение, содержащее специфичные для соединения поля заголовка, ДОЛЖНО рассматриваться как некорректное (раздел 8.1.2.6).

Единственным исключением является поле заголовка TE, которое МОЖЕТ присутствовать в запросе HTTP/2; когда это так, он НЕ ДОЛЖЕН содержать никаких значений, кроме «трейлеров».

Это означает, что посредник, преобразующий сообщение HTTP / 1.x в HTTP/2, должен будет удалить все поля заголовка, назначенные полем заголовка Connection, вместе с самим полем заголовка Connection. Таким посредникам СЛЕДУЕТ также удалять другие поля заголовка, относящиеся к конкретному соединению, такие как Keep-Alive, Proxy-Connection, Transfer-Encoding и Upgrade, даже если они не назначены полем заголовка Connection.

Примечание. HTTP/2 специально не поддерживает обновление до другого протокола. Методы рукопожатия, описанные в разделе 3, считаются достаточными для согласования использования альтернативных протоколов.

8.1.2.3. Запрос поля псевдо-заголовка

Следующие поля псевдо-заголовка определены для запросов HTTP/2:

o Поле псевдо-заголовка «:method» включает в себя метод HTTP ([RFC7231 #], раздел 4).

o Поле псевдо-заголовка «:scheme» включает в себя часть схемы целевого URI ([RFC3986 #], раздел 3.1).

«:scheme» не ограничена URI-схемами «http» и «https». Прокси-сервер или шлюз могут преобразовывать запросы для схем, отличных от HTTP, что позволяет использовать HTTP для взаимодействия со службами, отличными от HTTP.

o Поле псевдо-заголовка «:authority» включает в себя часть оснований целевого URI ([RFC3986 #], раздел 3.2). Основания НЕ ДОЛЖНЫ включать устаревший подкомпонент userinfo для URI схемы http или https.

Чтобы гарантировать, что строка запроса HTTP/1.1 может быть точно воспроизведена, это поле псевдо-заголовка ДОЛЖНО быть опущено при переводе из запроса HTTP/1.1, который имеет цель запроса в источнике или в форме звездочки (см. [RFC7230 #], раздел 5.3). Клиенты, которые генерируют запросы HTTP/2 напрямую, ДОЛЖНЫ использовать поле псевдо-заголовка «:authority» вместо поля заголовка хоста. Посредник, который преобразует запрос HTTP/2 в HTTP/1.1, ДОЛЖЕН создать поле заголовка хоста, если оно отсутствует в запросе, скопировав значение поля псевдо-заголовка «:authority«.

o Поле псевдо-заголовка «:path» включает в себя части пути и запроса целевого URI «path-absolute» (абсолютный путь) и, возможно, символ «?», за которым следует «query» (запрос) (см. разделы 3.3 и 3.4 из [ RFC3986 #]). Запрос в форме звездочки содержит значение ‘*’ для поля псевдо-заголовка «:path«.

Это поле псевдо-заголовка НЕ ​​ДОЛЖНО быть пустым для URI «http» или «https»; URI «http» или «https», которые не содержат компонент пути, ДОЛЖНЫ содержать значение «/». Исключением из этого правила является запрос OPTIONS для URI «http» или «https», который не включает компонент пути; они ДОЛЖНЫ включать поле псевдо-заголовка «:path» со значением «*» (см. [RFC7230 #], раздел 5.3.4).

Все запросы HTTP/2 ДОЛЖНЫ включать в себя ровно одно допустимое значение для полей псевдозаголовка «:method«, «:scheme«, «:path» («:метод», «:схема» и «:путь»), если только это не запрос CONNECT (раздел 8.3). HTTP-запрос, в котором пропущены обязательные поля псевдо-заголовка, искажен (раздел 8.1.2.6).

HTTP/2 не определяет способ переноса идентификатора версии, включенного в строку запроса HTTP/1.1.

8.1.2.4. Ответ поля псевдо-заголовка

Для ответов HTTP/2 определено одно поле псевдозаголовка «:status», которое содержит поле кода состояния HTTP (см. [RFC7231 #], раздел 6). Это поле псевдозаголовка ДОЛЖНО быть включено во все ответы; в противном случае ответ искажен (раздел 8.1.2.6).

HTTP/2 не определяет способ переноса версии или фразы причины, включенной в строку состояния HTTP/1.1.

Поле заголовка Cookie [COOKIE] использует точку с запятой («;») для разделения пар cookie (или «крошек»). Это поле заголовка не соответствует правилам построения списка в HTTP (см. [RFC7230 #], раздел 3.2.2), что предотвращает разделение пар cookie-файлов на разные пары имя-значение. Это может значительно снизить эффективность сжатия при обновлении отдельных пар cookie.

Чтобы обеспечить лучшую эффективность сжатия, поле заголовка Cookie МОЖЕТ быть разделено на отдельные поля заголовка, каждое из которых содержит одну или несколько пар cookie. Если после декомпрессии имеется несколько полей заголовка Cookie, они ДОЛЖНЫ быть объединены в одну строку октетов с использованием двухоктетного разделителя 0x3B, 0x20 (строка ASCII «;») перед передачей в не-HTTP/2-контекст, например как соединение HTTP/1.1, или универсальное приложение сервера HTTP.

Поэтому следующие два списка полей заголовка Cookie семантически эквивалентны.

cookie: a=b; c=d; e=f
cookie: a=b
cookie: c=d
cookie: e=f

8.1.2.6. Неверно сформированные запросы и ответы

Неверно сформированный запрос или ответ — это запрос, который в противном случае является действительной последовательностью кадров HTTP/2, но является недействительным из-за наличия посторонних кадров, запрещенных полей заголовка, отсутствия обязательных полей заголовка или включения имен полей заголовка верхнего регистра.

Запрос или ответ, который включает тело полезной нагрузки, может включать поле заголовка длины содержимого. Запрос или ответ также искажается, если значение поля заголовка длины содержимого не равно сумме длин полезной нагрузки кадра DATA, которые формируют тело. Ответ, который определен как не имеющий полезной нагрузки, как описано в [RFC7230 #], раздел 3.3.2, может иметь поле заголовка с ненулевой длиной содержимого, даже если содержимое не включено в кадры DATA.

Посредники, которые обрабатывают HTTP-запросы или ответы (т. Е. Любой посредник, не действующий в качестве туннеля), НЕ ДОЛЖНЫ пересылать искаженный запрос или ответ. Обнаруженные искаженные запросы или ответы ДОЛЖНЫ рассматриваться как ошибка потока (раздел 5.4.2) типа PROTOCOL_ERROR.

В случае некорректных запросов сервер МОЖЕТ отправить HTTP-ответ до закрытия или сброса потока. Клиенты НЕ ДОЛЖНЫ принимать некорректный ответ. Обратите внимание, что эти требования предназначены для защиты от нескольких типов распространенных атак на HTTP; они преднамеренно строги, потому что, будучи разрешительными, могут подвергнуть реализации этим уязвимостям.

8.1.3. Примеры

В этом разделе показаны запросы и ответы HTTP/1.1 с иллюстрациями эквивалентных запросов и ответов HTTP/2.

Запрос HTTP GET включает в себя поля заголовка запроса и не содержит тела полезной нагрузки и поэтому передается как один кадр HEADERS, за которым следует ноль или более кадров CONTINUATION, содержащих сериализованный блок полей заголовка запроса. В следующем кадре HEADERS установлены флаги END_HEADERS и END_STREAM; кадры ПРОДОЛЖЕНИЯ не отправляются.

GET /resource HTTP/1.1 ==> HEADERS
Host: example.org ==>==> + END_STREAM
Accept: image/jpeg==>==> + END_HEADERS
==>==>==>==>==>==>==>==>==>:method = GET
==>==>==>==>==>==>==>==>==>:scheme = https
==>==>==>==>==>==>==>==>==>:path = /resource
==>==>==>==>==>==>==>==>==>host = example.org
==>==>==>==>==>==>==>==>==>accept = image/jpeg

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

HTTP/1.1 304 Not Modified ==>HEADERS
ETag: "xyzzy" ==> ==> ==> ==> + END_STREAM
Expires: Thu, 23 Jan ...  ==> ==> + END_HEADERS
=====> ==> ==> ==> ==> ==>:status = 304
=====> ==> ==> ==> ==> ==>etag = "xyzzy"
=====> ==> ==> ==> ==> ==>expires = Thu, 23 Jan ...

Запрос HTTP POST, который включает в себя поля заголовка запроса и данные полезной нагрузки, передается в виде одного кадра HEADERS, за которым следует ноль или более кадров CONTINUATION, содержащих поля заголовка запроса, за которыми следует один или несколько кадров DATA, причем последний кадр CONTINUATION (или HEADERS) имеет установленный флаг END_HEADERS и последний кадр DATA, имеющий установленный флаг END_STREAM:

Запрос HTTP POST
Запрос HTTP POST

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

Ответ, который включает в себя поля заголовка и данные полезной нагрузки, передается в виде кадра HEADERS, за которым следуют ноль или более кадров CONTINUATION, затем один или несколько кадров DATA, причем последний кадр DATA в последовательности имеет установленный флаг END_STREAM:

Ответ с установленным флаг END_STREAM
Ответ с установленным флаг END_STREAM

Информационный ответ с использованием кода состояния 1xx, отличного от 101, передается в виде кадра HEADERS, за которым следует ноль или более кадров CONTINUATION.

Конечные поля заголовка отправляются в виде блока заголовка после того, как были отправлены блок заголовка запроса или ответа и все кадры DATA. Фрейм HEADERS, начинающий блок заголовка трейлера, имеет установленный флаг END_STREAM.

Следующий пример включает в себя как код состояния 100 (продолжение), который отправляется в ответ на запрос, содержащий маркер «100-continue» в поле заголовка Expect, так и поля конечного заголовка:

Ответ с кодом состояния 100
Ответ с кодом состояния 100

8.1.4. Запросить механизмы надежности в HTTP/2

В HTTP/1.1 HTTP-клиент не может повторить неидемпотентный запрос при возникновении ошибки, поскольку нет средств для определения характера ошибки. Возможно, что некоторая обработка на сервере произошла до ошибки, что может привести к нежелательным последствиям, если запрос будет повторен.

HTTP/2 предоставляет два механизма для предоставления клиенту гарантии того, что запрос не был обработан:

  • Кадр GOAWAY указывает наивысший номер потока, который мог быть обработан. Поэтому запросы на потоки с более высокими числами гарантированно безопасны для повторения.
  • Код ошибки REFUSED_STREAM может быть включен в кадр RST_STREAM, чтобы указать, что поток закрывается до какой-либо обработки. Любой запрос, который был отправлен в потоке сброса, можно безопасно повторить.

Запросы, которые не были обработаны, не потерпели неудачу; клиенты МОГУТ автоматически их повторять, даже с неидемпотентными методами.

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

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

8.2. Сервер Push

HTTP/2 позволяет серверу преимущественно отправлять (или «выдвигать») ответы (вместе с соответствующими «обещанными» запросами) клиенту в связи с предыдущим инициированным клиентом запросом. Это может быть полезно, когда сервер знает, что клиенту понадобятся эти ответы, чтобы полностью обработать ответ на исходный запрос.

Клиент может запросить отключение принудительной отправки сервера, хотя это согласовывается для каждого прыжка независимо. Параметр SETTINGS_ENABLE_PUSH может быть установлен в 0, чтобы указать, что принудительная загрузка сервера отключена.

Обещанные запросы ДОЛЖНЫ быть кешируемыми (см. [RFC7231 #], раздел 4.2.3), ДОЛЖНЫ быть безопасными (см. [RFC7231 #], раздел 4.2.1) и НЕ ДОЛЖНЫ включать тело запроса. Клиенты, которые получают обещанный запрос, который не может быть кэширован, неизвестно, является ли он безопасным или указывает на наличие тела запроса, ДОЛЖНЫ сбросить обещанный поток с ошибкой потока (раздел 5.4.2) типа PROTOCOL_ERROR. Обратите внимание, что это может привести к сбросу обещанного потока, если клиент не распознает вновь определенный метод как безопасный.

Отправленные ответы, которые могут быть кэшированы (см. [RFC7234 #], раздел 3), могут быть сохранены клиентом, если он реализует HTTP-кэш. Выдвинутые ответы считаются успешно проверенными на исходном сервере (например, если присутствует директива ответа кеша без кэширования ([RFC7234 #], раздел 5.2.2)), в то время как поток, идентифицируемый обещанным идентификатором потока, все еще открыт.

Отправленные ответы, которые не могут быть кэшированы, НЕ ДОЛЖНЫ храниться в каком-либо HTTP-кэше. Они МОГУТ быть предоставлены приложению отдельно.

Сервер ДОЛЖЕН включать значение в поле псевдозаголовка «: Права», для которого сервер является доверенным (см. Раздел 10.1). Клиент ДОЛЖЕН рассматривать PUSH_PROMISE, для которого сервер не является полномочным, как ошибку потока (раздел 5.4.2) типа PROTOCOL_ERROR.

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

Клиент не может подтолкнуть. Таким образом, серверы ДОЛЖНЫ трактовать получение кадра PUSH_PROMISE как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR. Клиенты ДОЛЖНЫ отклонить любую попытку изменить параметр SETTINGS_ENABLE_PUSH на значение, отличное от 0, обработав сообщение как ошибку соединения (раздел 5.4.1) типа PROTOCOL_ERROR.

8.2.1. Push-запросы

Push-сервер семантически эквивалентен серверу, отвечающему на запрос; однако в этом случае этот запрос также отправляется сервером как кадр PUSH_PROMISE.

Кадр PUSH_PROMISE включает в себя блок заголовка, который содержит полный набор полей заголовка запроса, которые сервер приписывает запросу. Невозможно отправить ответ на запрос, содержащий тело запроса.

Заданные ответы всегда связаны с явным запросом от клиента. Кадры PUSH_PROMISE, отправленные сервером, отправляются в потоке этого явного запроса. Кадр PUSH_PROMISE также включает в себя обещанный идентификатор потока, выбранный из идентификаторов потока, доступных для сервера (см. Раздел 5.1.1).

Поля заголовка в PUSH_PROMISE и любые последующие кадры CONTINUATION ДОЛЖНЫ быть действительным и полным набором полей заголовка запроса (Раздел 8.1.2.3).

Сервер ДОЛЖЕН включать метод в поле псевдозаголовка «:method«, который является безопасным и кэшируемым. Если клиент получает PUSH_PROMISE, который не включает в себя полный и действительный набор полей заголовка, или поле псевдо-заголовка «:method» идентифицирует небезопасный метод, он ДОЛЖЕН ответить ошибкой потока (раздел 5.4.2) введите PROTOCOL_ERROR.

Сервер ДОЛЖЕН послать кадры PUSH_PROMISE (раздел 6.6) до отправки любых кадров, которые ссылаются на обещанные ответы. Это позволяет избежать гонки, в которой клиенты выдают запросы до получения любых кадров PUSH_PROMISE.

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

Кадры PUSH_PROMISE могут отправляться сервером в ответ на любой инициированный клиентом поток, но поток ДОЛЖЕН находиться в состоянии «открыто» или «полузакрыто (удаленно)» по отношению к серверу.

Кадры PUSH_PROMISE перемежаются с кадрами, которые составляют ответ, хотя они не могут перемежаться с кадрами HEADERS и CONTINUATION, которые составляют один блок заголовка.

Отправка кадра PUSH_PROMISE создает новый поток и переводит поток в «зарезервированное (локальное)» состояние для сервера и в «зарезервированное (удаленное)» состояние для клиента.

8.2.2. Push-ответы

После отправки кадра PUSH_PROMISE сервер может начать доставку отправленного ответа в качестве ответа (раздел 8.1.2.4) в инициированном сервером потоке, который использует обещанный идентификатор потока. Сервер использует этот поток для передачи ответа HTTP, используя ту же последовательность кадров, как определено в разделе 8.1. Этот поток становится «полузакрытым» для клиента (раздел 5.1) после отправки начального кадра HEADERS.

Как только клиент получает кадр PUSH_PROMISE и выбирает принять отправленный ответ, клиент НЕ ДОЛЖЕН выдавать какие-либо запросы на обещанный ответ до тех пор, пока обещанный поток не будет закрыт.

Если клиент по какой-либо причине определяет, что он не хочет получать отправленный ответ от сервера или если серверу требуется слишком много времени, чтобы начать отправку обещанного ответа, клиент может отправить кадр RST_STREAM, используя либо CANCEL, либо REFUSED_STREAM. код и ссылка на идентификатор выдвигаемого потока.

Клиент может использовать параметр SETTINGS_MAX_CONCURRENT_STREAMS, чтобы ограничить количество ответов, которые могут быть одновременно отправлены сервером. Объявление нулевого значения SETTINGS_MAX_CONCURRENT_STREAMS отключает принудительную передачу сервера, не позволяя серверу создавать необходимые потоки. Это не запрещает серверу отправлять кадры PUSH_PROMISE; клиенты должны сбросить любые обещанные потоки, которые не нужны.

Клиенты, получающие отправленный ответ, ДОЛЖНЫ подтвердить, что либо сервер является доверенным (см. Раздел 10.1), либо прокси-сервер, предоставивший отправленный ответ, настроен для соответствующего запроса. Например, серверу, который предлагает сертификат только для DNS-идентификатора или общего имени «example.com», не разрешается выдвигать ответ для «https://www.example.org/doc».

Ответ для потока PUSH_PROMISE начинается с кадра HEADERS, который немедленно переводит поток в состояние «полузакрытый (удаленный)» для сервера и состояние «полузакрытый (локальный)» для клиента, и заканчивается кадром несущий END_STREAM, который переводит поток в «закрытое» состояние.

Примечание. Клиент никогда не отправляет кадр с флагом END_STREAM для отправки на сервер.

8.3. Метод CONNECT

В HTTP/1.x псевдо-метод CONNECT ([RFC7231 #], раздел 4.3.6) используется для преобразования HTTP-соединения в туннель на удаленный хост. CONNECT в основном используется с прокси-серверами HTTP для установления сеанса TLS с исходным сервером для взаимодействия с ресурсами https.

В HTTP/2 метод CONNECT используется для установки туннеля по одному потоку HTTP/2 на удаленный хост для аналогичных целей. Отображение полей заголовка HTTP работает, как определено в Разделе 8.1.2.3 («Запрос полей псевдозаголовка»), с некоторыми отличиями. В частности:

  • Поле псевдо-заголовка «:method» установлено в «CONNECT».
  • Поля псевдо-заголовка «:scheme» и «:path» ДОЛЖНЫ быть опущены.
  • Поле псевдо-заголовка «:authority» содержит хост и порт для подключения (эквивалентно форме оснований объекта-запроса запросов CONNECT (см. [RFC7230 #], Раздел 5.3)).

Запрос CONNECT, который не соответствует этим ограничениям, искажен (Раздел 8.1.2.6).

Прокси-сервер, который поддерживает CONNECT, устанавливает TCP-соединение [TCP] с сервером, указанным в поле псевдозаголовка «:authority«. Как только это соединение успешно установлено, прокси-сервер отправляет клиенту кадр HEADERS, содержащий код состояния серии 2xx, как определено в [RFC7231 #], раздел 4.3.6.

После начального кадра HEADERS, отправленного каждым узлом, все последующие кадры DATA соответствуют данным, отправленным по TCP-соединению. Полезная нагрузка любых фреймов DATA, отправленных клиентом, передается через прокси на TCP-сервер; данные, полученные с сервера TCP, собираются прокси в кадры DATA. Типы кадров, отличные от DATA или кадров управления потоком (RST_STREAM, WINDOW_UPDATE и PRIORITY), НЕ ДОЛЖНЫ отправляться в подключенном потоке и ДОЛЖНЫ рассматриваться как ошибка потока (раздел 5.4.2), если они получены.

Соединение TCP может быть закрыто любым узлом. Флаг END_STREAM в кадре DATA рассматривается как эквивалентный биту FIN FIN. Ожидается, что клиент отправит кадр DATA с установленным флагом END_STREAM после получения кадра с флагом END_STREAM. Прокси-сервер, который получает фрейм DATA с установленным флагом END_STREAM, отправляет прикрепленные данные с битом FIN, установленным в последнем сегменте TCP. Прокси-сервер, который получает сегмент TCP с установленным битом FIN, отправляет кадр DATA с установленным флагом END_STREAM. Обратите внимание, что последний сегмент TCP или кадр DATA могут быть пустыми.

Ошибка соединения TCP сообщается с помощью RST_STREAM. Прокси-сервер обрабатывает любую ошибку в соединении TCP, которая включает получение сегмента TCP с установленным битом RST, как ошибку потока (раздел 5.4.2) типа CONNECT_ERROR. Соответственно, прокси-сервер ДОЛЖЕН послать сегмент TCP с установленным битом RST, если обнаружит ошибку в потоке или соединении HTTP/2.

9. Дополнительные требования HTTP / соображения

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

9.1. Управление подключением

HTTP/2 соединения постоянны. Для достижения максимальной производительности ожидается, что клиенты не будут закрывать соединения, пока не будет определено, что дальнейшая связь с сервером не требуется (например, когда пользователь уходит с определенной веб-страницы) или пока сервер не закроет соединение.

Клиентам НЕ СЛЕДУЕТ открывать более одного соединения HTTP/2 с данной парой хоста и порта, где хост получен из URI, выбранной альтернативной службы [ALT-SVC] или настроенного прокси.

Клиент может создавать дополнительные соединения в качестве замены, либо для замены соединений, которые близки к исчерпанию доступного пространства идентификатора потока (раздел 5.1.1), либо для обновления материала ключей для соединения TLS, либо для замены соединений, в которых возникли ошибки (раздел 5.4.1).

Клиент МОЖЕТ открыть несколько соединений с одним и тем же IP-адресом и портом TCP, используя разные значения Индикации имени сервера [TLS-EXT] или предоставить разные клиентские сертификаты TLS, но СЛЕДУЕТ избегать создания нескольких соединений с одной и той же конфигурацией.

Серверам рекомендуется поддерживать открытые соединения как можно дольше, но при необходимости им разрешается прерывать неактивные соединения. Когда одна из конечных точек решает закрыть TCP-соединение транспортного уровня, конечная точка ДОЛЖНА сначала отправить кадр GOAWAY (раздел 6.8), чтобы обе конечные точки могли надежно определить, были ли обработаны ранее отправленные кадры, изящно завершить или завершить любые необходимые оставшиеся задачи.

9.1.1. Повторное использование подключения

Соединения, которые устанавливаются на исходный сервер, либо напрямую, либо через туннель, созданный с использованием метода CONNECT (раздел 8.3), МОГУТ использоваться повторно для запросов с несколькими различными компонентами оснований URI. Соединение может быть повторно использовано, если исходный сервер является полномочным (Раздел 10.1). Для TCP-соединений без TLS это зависит от того, что хост разрешен к тому же IP-адресу.

Для ресурсов «https» повторное использование соединения дополнительно зависит от наличия сертификата, действительного для хоста в URI. Сертификат, представленный сервером, ДОЛЖЕН удовлетворять любые проверки, которые клиент будет выполнять при формировании нового соединения TLS для хоста в URI.

Исходный сервер может предлагать сертификат с несколькими атрибутами «subjectAltName» или именами с подстановочными знаками, один из которых действителен для оснований в URI. Например, сертификат с «subjectAltName», равным «* .example.com», может разрешить использовани