Packages

QPACK header compression for HTTP/3 (RFC 9204)

Current section

Files

Jump to
qpack src qpack_static_table.hrl
Raw

src/qpack_static_table.hrl

%%% -*- erlang -*-
%%%
%%% This file is part of erlang_qpack released under the Apache 2 license.
%%% See the NOTICE for more information.
%%%
%%% Copyright (c) 2024-2026 Benoit Chesneau
%%%
%%% @doc QPACK Static Table (RFC 9204 Appendix A).
%%%
%%% The static table contains 99 pre-defined header fields (indices 0-98).
%%% This file provides:
%%% - Tuple for O(1) index-to-entry lookup
%%% - Map for O(1) exact header match lookup
%%% - Map for O(1) name-only lookup
%%% @end
%% Entry overhead per RFC 9204 Section 3.2.1
-define(ENTRY_OVERHEAD, 32).
%% Static table as tuple for O(1) index access (0-98)
-define(STATIC_TABLE, {
%% 0-14
{<<":authority">>, undefined},
{<<":path">>, <<"/">>},
{<<":age">>, <<"0">>},
{<<"content-disposition">>, undefined},
{<<"content-length">>, <<"0">>},
{<<"cookie">>, undefined},
{<<"date">>, undefined},
{<<"etag">>, undefined},
{<<"if-modified-since">>, undefined},
{<<"if-none-match">>, undefined},
{<<"last-modified">>, undefined},
{<<"link">>, undefined},
{<<"location">>, undefined},
{<<"referer">>, undefined},
{<<"set-cookie">>, undefined},
%% 15-29
{<<":method">>, <<"CONNECT">>},
{<<":method">>, <<"DELETE">>},
{<<":method">>, <<"GET">>},
{<<":method">>, <<"HEAD">>},
{<<":method">>, <<"OPTIONS">>},
{<<":method">>, <<"POST">>},
{<<":method">>, <<"PUT">>},
{<<":scheme">>, <<"http">>},
{<<":scheme">>, <<"https">>},
{<<":status">>, <<"103">>},
{<<":status">>, <<"200">>},
{<<":status">>, <<"304">>},
{<<":status">>, <<"404">>},
{<<":status">>, <<"503">>},
{<<"accept">>, <<"*/*">>},
%% 30-44
{<<"accept">>, <<"application/dns-message">>},
{<<"accept-encoding">>, <<"gzip, deflate, br">>},
{<<"accept-ranges">>, <<"bytes">>},
{<<"access-control-allow-headers">>, <<"cache-control">>},
{<<"access-control-allow-headers">>, <<"content-type">>},
{<<"access-control-allow-origin">>, <<"*">>},
{<<"cache-control">>, <<"max-age=0">>},
{<<"cache-control">>, <<"max-age=2592000">>},
{<<"cache-control">>, <<"max-age=604800">>},
{<<"cache-control">>, <<"no-cache">>},
{<<"cache-control">>, <<"no-store">>},
{<<"cache-control">>, <<"public, max-age=31536000">>},
{<<"content-encoding">>, <<"br">>},
{<<"content-encoding">>, <<"gzip">>},
{<<"content-type">>, <<"application/dns-message">>},
%% 45-59
{<<"content-type">>, <<"application/javascript">>},
{<<"content-type">>, <<"application/json">>},
{<<"content-type">>, <<"application/x-www-form-urlencoded">>},
{<<"content-type">>, <<"image/gif">>},
{<<"content-type">>, <<"image/jpeg">>},
{<<"content-type">>, <<"image/png">>},
{<<"content-type">>, <<"text/css">>},
{<<"content-type">>, <<"text/html; charset=utf-8">>},
{<<"content-type">>, <<"text/plain">>},
{<<"content-type">>, <<"text/plain;charset=utf-8">>},
{<<"range">>, <<"bytes=0-">>},
{<<"strict-transport-security">>, <<"max-age=31536000">>},
{<<"strict-transport-security">>, <<"max-age=31536000; includesubdomains">>},
{<<"strict-transport-security">>, <<"max-age=31536000; includesubdomains; preload">>},
{<<"vary">>, <<"accept-encoding">>},
%% 60-74
{<<"vary">>, <<"origin">>},
{<<"x-content-type-options">>, <<"nosniff">>},
{<<"x-xss-protection">>, <<"1; mode=block">>},
{<<":status">>, <<"100">>},
{<<":status">>, <<"204">>},
{<<":status">>, <<"206">>},
{<<":status">>, <<"302">>},
{<<":status">>, <<"400">>},
{<<":status">>, <<"403">>},
{<<":status">>, <<"421">>},
{<<":status">>, <<"425">>},
{<<":status">>, <<"500">>},
{<<"accept-language">>, undefined},
{<<"access-control-allow-credentials">>, <<"FALSE">>},
{<<"access-control-allow-credentials">>, <<"TRUE">>},
%% 75-89
{<<"access-control-allow-headers">>, <<"*">>},
{<<"access-control-allow-methods">>, <<"get">>},
{<<"access-control-allow-methods">>, <<"get, post, options">>},
{<<"access-control-allow-methods">>, <<"options">>},
{<<"access-control-expose-headers">>, <<"content-length">>},
{<<"access-control-request-headers">>, <<"content-type">>},
{<<"access-control-request-method">>, <<"get">>},
{<<"access-control-request-method">>, <<"post">>},
{<<"alt-svc">>, <<"clear">>},
{<<"authorization">>, undefined},
{<<"content-security-policy">>, <<"script-src 'none'; object-src 'none'; base-uri 'none'">>},
{<<"early-data">>, <<"1">>},
{<<"expect-ct">>, undefined},
{<<"forwarded">>, undefined},
{<<"if-range">>, undefined},
%% 90-98
{<<"origin">>, undefined},
{<<"purpose">>, <<"prefetch">>},
{<<"server">>, undefined},
{<<"timing-allow-origin">>, <<"*">>},
{<<"upgrade-insecure-requests">>, <<"1">>},
{<<"user-agent">>, undefined},
{<<"x-forwarded-for">>, undefined},
{<<"x-frame-options">>, <<"deny">>},
{<<"x-frame-options">>, <<"sameorigin">>}
}).
%% Static table field map for O(1) exact match lookup
%% Maps {Name, Value} -> Index
-define(STATIC_FIELD_MAP, #{
{<<":path">>, <<"/">>} => 1,
{<<":age">>, <<"0">>} => 2,
{<<"content-length">>, <<"0">>} => 4,
{<<":method">>, <<"CONNECT">>} => 15,
{<<":method">>, <<"DELETE">>} => 16,
{<<":method">>, <<"GET">>} => 17,
{<<":method">>, <<"HEAD">>} => 18,
{<<":method">>, <<"OPTIONS">>} => 19,
{<<":method">>, <<"POST">>} => 20,
{<<":method">>, <<"PUT">>} => 21,
{<<":scheme">>, <<"http">>} => 22,
{<<":scheme">>, <<"https">>} => 23,
{<<":status">>, <<"103">>} => 24,
{<<":status">>, <<"200">>} => 25,
{<<":status">>, <<"304">>} => 26,
{<<":status">>, <<"404">>} => 27,
{<<":status">>, <<"503">>} => 28,
{<<"accept">>, <<"*/*">>} => 29,
{<<"accept">>, <<"application/dns-message">>} => 30,
{<<"accept-encoding">>, <<"gzip, deflate, br">>} => 31,
{<<"accept-ranges">>, <<"bytes">>} => 32,
{<<"access-control-allow-headers">>, <<"cache-control">>} => 33,
{<<"access-control-allow-headers">>, <<"content-type">>} => 34,
{<<"access-control-allow-origin">>, <<"*">>} => 35,
{<<"cache-control">>, <<"max-age=0">>} => 36,
{<<"cache-control">>, <<"max-age=2592000">>} => 37,
{<<"cache-control">>, <<"max-age=604800">>} => 38,
{<<"cache-control">>, <<"no-cache">>} => 39,
{<<"cache-control">>, <<"no-store">>} => 40,
{<<"cache-control">>, <<"public, max-age=31536000">>} => 41,
{<<"content-encoding">>, <<"br">>} => 42,
{<<"content-encoding">>, <<"gzip">>} => 43,
{<<"content-type">>, <<"application/dns-message">>} => 44,
{<<"content-type">>, <<"application/javascript">>} => 45,
{<<"content-type">>, <<"application/json">>} => 46,
{<<"content-type">>, <<"application/x-www-form-urlencoded">>} => 47,
{<<"content-type">>, <<"image/gif">>} => 48,
{<<"content-type">>, <<"image/jpeg">>} => 49,
{<<"content-type">>, <<"image/png">>} => 50,
{<<"content-type">>, <<"text/css">>} => 51,
{<<"content-type">>, <<"text/html; charset=utf-8">>} => 52,
{<<"content-type">>, <<"text/plain">>} => 53,
{<<"content-type">>, <<"text/plain;charset=utf-8">>} => 54,
{<<"range">>, <<"bytes=0-">>} => 55,
{<<"strict-transport-security">>, <<"max-age=31536000">>} => 56,
{<<"strict-transport-security">>, <<"max-age=31536000; includesubdomains">>} => 57,
{<<"strict-transport-security">>, <<"max-age=31536000; includesubdomains; preload">>} => 58,
{<<"vary">>, <<"accept-encoding">>} => 59,
{<<"vary">>, <<"origin">>} => 60,
{<<"x-content-type-options">>, <<"nosniff">>} => 61,
{<<"x-xss-protection">>, <<"1; mode=block">>} => 62,
{<<":status">>, <<"100">>} => 63,
{<<":status">>, <<"204">>} => 64,
{<<":status">>, <<"206">>} => 65,
{<<":status">>, <<"302">>} => 66,
{<<":status">>, <<"400">>} => 67,
{<<":status">>, <<"403">>} => 68,
{<<":status">>, <<"421">>} => 69,
{<<":status">>, <<"425">>} => 70,
{<<":status">>, <<"500">>} => 71,
{<<"access-control-allow-credentials">>, <<"FALSE">>} => 73,
{<<"access-control-allow-credentials">>, <<"TRUE">>} => 74,
{<<"access-control-allow-headers">>, <<"*">>} => 75,
{<<"access-control-allow-methods">>, <<"get">>} => 76,
{<<"access-control-allow-methods">>, <<"get, post, options">>} => 77,
{<<"access-control-allow-methods">>, <<"options">>} => 78,
{<<"access-control-expose-headers">>, <<"content-length">>} => 79,
{<<"access-control-request-headers">>, <<"content-type">>} => 80,
{<<"access-control-request-method">>, <<"get">>} => 81,
{<<"access-control-request-method">>, <<"post">>} => 82,
{<<"alt-svc">>, <<"clear">>} => 83,
{<<"content-security-policy">>, <<"script-src 'none'; object-src 'none'; base-uri 'none'">>} => 85,
{<<"early-data">>, <<"1">>} => 86,
{<<"purpose">>, <<"prefetch">>} => 91,
{<<"timing-allow-origin">>, <<"*">>} => 93,
{<<"upgrade-insecure-requests">>, <<"1">>} => 94,
{<<"x-frame-options">>, <<"deny">>} => 97,
{<<"x-frame-options">>, <<"sameorigin">>} => 98
}).
%% Static table name map for O(1) name-only lookup
%% Maps Name -> Index (first occurrence of that name)
-define(STATIC_NAME_MAP, #{
<<":authority">> => 0,
<<":path">> => 1,
<<":age">> => 2,
<<"content-disposition">> => 3,
<<"content-length">> => 4,
<<"cookie">> => 5,
<<"date">> => 6,
<<"etag">> => 7,
<<"if-modified-since">> => 8,
<<"if-none-match">> => 9,
<<"last-modified">> => 10,
<<"link">> => 11,
<<"location">> => 12,
<<"referer">> => 13,
<<"set-cookie">> => 14,
<<":method">> => 15,
<<":scheme">> => 22,
<<":status">> => 24,
<<"accept">> => 29,
<<"accept-encoding">> => 31,
<<"accept-ranges">> => 32,
<<"access-control-allow-headers">> => 33,
<<"access-control-allow-origin">> => 35,
<<"cache-control">> => 36,
<<"content-encoding">> => 42,
<<"content-type">> => 44,
<<"range">> => 55,
<<"strict-transport-security">> => 56,
<<"vary">> => 59,
<<"x-content-type-options">> => 61,
<<"x-xss-protection">> => 62,
<<"accept-language">> => 72,
<<"access-control-allow-credentials">> => 73,
<<"access-control-allow-methods">> => 76,
<<"access-control-expose-headers">> => 79,
<<"access-control-request-headers">> => 80,
<<"access-control-request-method">> => 81,
<<"alt-svc">> => 83,
<<"authorization">> => 84,
<<"content-security-policy">> => 85,
<<"early-data">> => 86,
<<"expect-ct">> => 87,
<<"forwarded">> => 88,
<<"if-range">> => 89,
<<"origin">> => 90,
<<"purpose">> => 91,
<<"server">> => 92,
<<"timing-allow-origin">> => 93,
<<"upgrade-insecure-requests">> => 94,
<<"user-agent">> => 95,
<<"x-forwarded-for">> => 96,
<<"x-frame-options">> => 97
}).