%%% -*- 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 }).