Post #610
156
А, да, HPACK. В HTTP/2 решили, что хорошей идеей будет сжимать заголовки. Что, в общем-то, и правда хорошая идея. Правильная, я бы даже сказал. Чем полагаться на обычные компрессоры, решили сделать лучше - и сварганили свою схему кодирования, гордо именуемую HPACK, и вынесенную аж в отдельный RFC7541 (сам HTTP/2 живёт в RFC7540). Не просто так, кстати: таким образом, они хотели обезопасить шпак от изменений в будущих HTTP/2 RFC. Да и в целом они его максимально негибким сделали, чтобы никто его никак не вертел без того, чтобы новый RFC публиковать. Так и вышло: для HTTP/3 схему всё-таки подкрутили, и опубликовали, как QPACK.
Ну и вот, в HTTP/2 HEADERS фреймах (ну или же CONTINUATION, если же в соответствующем стейте) передаются как раз заголовки в формате HPACK. "Поле", как они называются (решили абстрагироваться от "заголовок"), может быть одно из 5 типов:
1. Полная пара из таблицы
2. Ключ возможно в таблице, значение вот
3. Как 2, только в таблицу не добавляется
4. Как 2, только в таблицу НИ В КОЕМ СЛУЧАЕ не добавляется.
4 - это всякие сенситив заголовки а-ля токены аутентификации. Отличие от 3 в том, что intermediaries (они же всеразличные прокси и их друзья) обязаны также передать этот заголовок дальше, как never indexed.
5. Изменение размера таблицы - не так интересно, опустим.
Углубляться в то, как оно выглядит, я не буду. Для этого я оставил номер RFC🫶
Собственно, таблица, сердце всей схемы. Она делится на две части: статическая и динамическая. Они делят общее индексное пространство, но новые значения добавляются, понятно, только в динамическую. Таблица эта хранит целые пары заголовков - и ключ, и значение. В статической, правда, добрые 2/3 с пустыми значениями, но оно и понятно - они там только ради ключей. Ну, то есть, а хули в качестве значения для cookie давать?
Статическая таблица вмещает 60 пар, индексируется с единицы (потому что индекс 0 зарезервирован для литеральных ключей). То есть, динамическая таблица начинается с индекса 62. Вообще, она сама по себе интересна: при добавлении новой пары, она встаёт в самое начало, т.е. на индекс 62. Все предыдущие, соответственно, сдвигаются на +1. Когда максимальный размер таблицы превышается, самые старые вхождения дропаются до тех пор, пока новая пара не поместится. Попытаться засунуть 10-мегабайтный заголовок в таблицу на 4096 байт это не ошибка, кстати, просто таблица окажется пустой - все старые значения дропнутся, а новое один хуй не влезет. Правда, есть и более гуманные способы её очистить.
Ещё есть забавный момент, потому что ключ новой добавляемой пары может ссылаться на уже лежащий в таблице. И тогда может возникнуть нюанс, что ключ, на который как раз и ссылается новое вхождение, находится в конце и должен быть дропнут. Тогда у нас магическим образом возникает dangling pointer, только dangling index. Тоже об этом в стандарте предупреждают. Слава богу, что мене це не бентежить, я монофаллически держу всё в закольцованном буфере.
Ну и вот, в HTTP/2 HEADERS фреймах (ну или же CONTINUATION, если же в соответствующем стейте) передаются как раз заголовки в формате HPACK. "Поле", как они называются (решили абстрагироваться от "заголовок"), может быть одно из 5 типов:
1. Полная пара из таблицы
2. Ключ возможно в таблице, значение вот
3. Как 2, только в таблицу не добавляется
4. Как 2, только в таблицу НИ В КОЕМ СЛУЧАЕ не добавляется.
4 - это всякие сенситив заголовки а-ля токены аутентификации. Отличие от 3 в том, что intermediaries (они же всеразличные прокси и их друзья) обязаны также передать этот заголовок дальше, как never indexed.
5. Изменение размера таблицы - не так интересно, опустим.
Углубляться в то, как оно выглядит, я не буду. Для этого я оставил номер RFC🫶
Собственно, таблица, сердце всей схемы. Она делится на две части: статическая и динамическая. Они делят общее индексное пространство, но новые значения добавляются, понятно, только в динамическую. Таблица эта хранит целые пары заголовков - и ключ, и значение. В статической, правда, добрые 2/3 с пустыми значениями, но оно и понятно - они там только ради ключей. Ну, то есть, а хули в качестве значения для cookie давать?
Статическая таблица вмещает 60 пар, индексируется с единицы (потому что индекс 0 зарезервирован для литеральных ключей). То есть, динамическая таблица начинается с индекса 62. Вообще, она сама по себе интересна: при добавлении новой пары, она встаёт в самое начало, т.е. на индекс 62. Все предыдущие, соответственно, сдвигаются на +1. Когда максимальный размер таблицы превышается, самые старые вхождения дропаются до тех пор, пока новая пара не поместится. Попытаться засунуть 10-мегабайтный заголовок в таблицу на 4096 байт это не ошибка, кстати, просто таблица окажется пустой - все старые значения дропнутся, а новое один хуй не влезет. Правда, есть и более гуманные способы её очистить.
Ещё есть забавный момент, потому что ключ новой добавляемой пары может ссылаться на уже лежащий в таблице. И тогда может возникнуть нюанс, что ключ, на который как раз и ссылается новое вхождение, находится в конце и должен быть дропнут. Тогда у нас магическим образом возникает dangling pointer, только dangling index. Тоже об этом в стандарте предупреждают. Слава богу, что мене це не бентежить, я монофаллически держу всё в закольцованном буфере.






