aboutsummaryrefslogtreecommitdiffstats
path: root/epan/nghttp2/nghttp2_hd.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/nghttp2/nghttp2_hd.c')
-rw-r--r--epan/nghttp2/nghttp2_hd.c1001
1 files changed, 709 insertions, 292 deletions
diff --git a/epan/nghttp2/nghttp2_hd.c b/epan/nghttp2/nghttp2_hd.c
index 81726cd5f1..2f0c00228a 100644
--- a/epan/nghttp2/nghttp2_hd.c
+++ b/epan/nghttp2/nghttp2_hd.c
@@ -31,118 +31,472 @@
#include "nghttp2_helper.h"
#include "nghttp2_int.h"
-#define STATIC_TABLE_LENGTH 61
-
-/* Make scalar initialization form of nghttp2_nv */
-#define MAKE_STATIC_ENT(I, N, V, NH, VH) \
+/* Make scalar initialization form of nghttp2_hd_entry */
+#define MAKE_STATIC_ENT(N, V, T) \
{ \
- { \
- { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \
- , (NH), (VH), 1, NGHTTP2_HD_FLAG_NONE \
- } \
- , I \
+ { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \
+ , (T), 1, NGHTTP2_HD_FLAG_NONE \
}
/* Generated by mkstatictbl.py */
-/* Sorted by hash(name) and its table index */
-static nghttp2_hd_static_entry static_table[] = {
- MAKE_STATIC_ENT(20, "age", "", 96511u, 0u),
- MAKE_STATIC_ENT(59, "via", "", 116750u, 0u),
- MAKE_STATIC_ENT(32, "date", "", 3076014u, 0u),
- MAKE_STATIC_ENT(33, "etag", "", 3123477u, 0u),
- MAKE_STATIC_ENT(36, "from", "", 3151786u, 0u),
- MAKE_STATIC_ENT(37, "host", "", 3208616u, 0u),
- MAKE_STATIC_ENT(44, "link", "", 3321850u, 0u),
- MAKE_STATIC_ENT(58, "vary", "", 3612210u, 0u),
- MAKE_STATIC_ENT(38, "if-match", "", 34533653u, 0u),
- MAKE_STATIC_ENT(41, "if-range", "", 39145613u, 0u),
- MAKE_STATIC_ENT(3, ":path", "/", 56997727u, 47u),
- MAKE_STATIC_ENT(4, ":path", "/index.html", 56997727u, 2144181430u),
- MAKE_STATIC_ENT(21, "allow", "", 92906313u, 0u),
- MAKE_STATIC_ENT(49, "range", "", 108280125u, 0u),
- MAKE_STATIC_ENT(14, "accept-charset", "", 124285319u, 0u),
- MAKE_STATIC_ENT(43, "last-modified", "", 150043680u, 0u),
- MAKE_STATIC_ENT(48, "proxy-authorization", "", 329532250u, 0u),
- MAKE_STATIC_ENT(57, "user-agent", "", 486342275u, 0u),
- MAKE_STATIC_ENT(40, "if-none-match", "", 646073760u, 0u),
- MAKE_STATIC_ENT(30, "content-type", "", 785670158u, 0u),
- MAKE_STATIC_ENT(16, "accept-language", "", 802785917u, 0u),
- MAKE_STATIC_ENT(50, "referer", "", 1085069613u, 0u),
- MAKE_STATIC_ENT(51, "refresh", "", 1085444827u, 0u),
- MAKE_STATIC_ENT(55, "strict-transport-security", "", 1153852136u, 0u),
- MAKE_STATIC_ENT(54, "set-cookie", "", 1237214767u, 0u),
- MAKE_STATIC_ENT(56, "transfer-encoding", "", 1274458357u, 0u),
- MAKE_STATIC_ENT(17, "accept-ranges", "", 1397189435u, 0u),
- MAKE_STATIC_ENT(42, "if-unmodified-since", "", 1454068927u, 0u),
- MAKE_STATIC_ENT(46, "max-forwards", "", 1619948695u, 0u),
- MAKE_STATIC_ENT(45, "location", "", 1901043637u, 0u),
- MAKE_STATIC_ENT(52, "retry-after", "", 1933352567u, 0u),
- MAKE_STATIC_ENT(25, "content-encoding", "", 2095084583u, 0u),
- MAKE_STATIC_ENT(28, "content-location", "", 2284906121u, 0u),
- MAKE_STATIC_ENT(39, "if-modified-since", "", 2302095846u, 0u),
- MAKE_STATIC_ENT(18, "accept", "", 2871506184u, 0u),
- MAKE_STATIC_ENT(29, "content-range", "", 2878374633u, 0u),
- MAKE_STATIC_ENT(22, "authorization", "", 2909397113u, 0u),
- MAKE_STATIC_ENT(31, "cookie", "", 2940209764u, 0u),
- MAKE_STATIC_ENT(0, ":authority", "", 2962729033u, 0u),
- MAKE_STATIC_ENT(35, "expires", "", 2985731892u, 0u),
- MAKE_STATIC_ENT(34, "expect", "", 3005803609u, 0u),
- MAKE_STATIC_ENT(24, "content-disposition", "", 3027699811u, 0u),
- MAKE_STATIC_ENT(26, "content-language", "", 3065240108u, 0u),
- MAKE_STATIC_ENT(1, ":method", "GET", 3153018267u, 70454u),
- MAKE_STATIC_ENT(2, ":method", "POST", 3153018267u, 2461856u),
- MAKE_STATIC_ENT(27, "content-length", "", 3162187450u, 0u),
- MAKE_STATIC_ENT(19, "access-control-allow-origin", "", 3297999203u, 0u),
- MAKE_STATIC_ENT(5, ":scheme", "http", 3322585695u, 3213448u),
- MAKE_STATIC_ENT(6, ":scheme", "https", 3322585695u, 99617003u),
- MAKE_STATIC_ENT(7, ":status", "200", 3338091692u, 49586u),
- MAKE_STATIC_ENT(8, ":status", "204", 3338091692u, 49590u),
- MAKE_STATIC_ENT(9, ":status", "206", 3338091692u, 49592u),
- MAKE_STATIC_ENT(10, ":status", "304", 3338091692u, 50551u),
- MAKE_STATIC_ENT(11, ":status", "400", 3338091692u, 51508u),
- MAKE_STATIC_ENT(12, ":status", "404", 3338091692u, 51512u),
- MAKE_STATIC_ENT(13, ":status", "500", 3338091692u, 52469u),
- MAKE_STATIC_ENT(53, "server", "", 3389140803u, 0u),
- MAKE_STATIC_ENT(47, "proxy-authenticate", "", 3993199572u, 0u),
- MAKE_STATIC_ENT(60, "www-authenticate", "", 4051929931u, 0u),
- MAKE_STATIC_ENT(23, "cache-control", "", 4086191634u, 0u),
- MAKE_STATIC_ENT(15, "accept-encoding", "gzip, deflate", 4127597688u,
- 1733326877u),
+/* 3rd parameter is nghttp2_token value for header field name. We use
+ first enum value if same header names are repeated (e.g.,
+ :status). */
+static nghttp2_hd_entry static_table[] = {
+ MAKE_STATIC_ENT(":authority", "", 0),
+ MAKE_STATIC_ENT(":method", "GET", 1),
+ MAKE_STATIC_ENT(":method", "POST", 1),
+ MAKE_STATIC_ENT(":path", "/", 3),
+ MAKE_STATIC_ENT(":path", "/index.html", 3),
+ MAKE_STATIC_ENT(":scheme", "http", 5),
+ MAKE_STATIC_ENT(":scheme", "https", 5),
+ MAKE_STATIC_ENT(":status", "200", 7),
+ MAKE_STATIC_ENT(":status", "204", 7),
+ MAKE_STATIC_ENT(":status", "206", 7),
+ MAKE_STATIC_ENT(":status", "304", 7),
+ MAKE_STATIC_ENT(":status", "400", 7),
+ MAKE_STATIC_ENT(":status", "404", 7),
+ MAKE_STATIC_ENT(":status", "500", 7),
+ MAKE_STATIC_ENT("accept-charset", "", 14),
+ MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15),
+ MAKE_STATIC_ENT("accept-language", "", 16),
+ MAKE_STATIC_ENT("accept-ranges", "", 17),
+ MAKE_STATIC_ENT("accept", "", 18),
+ MAKE_STATIC_ENT("access-control-allow-origin", "", 19),
+ MAKE_STATIC_ENT("age", "", 20),
+ MAKE_STATIC_ENT("allow", "", 21),
+ MAKE_STATIC_ENT("authorization", "", 22),
+ MAKE_STATIC_ENT("cache-control", "", 23),
+ MAKE_STATIC_ENT("content-disposition", "", 24),
+ MAKE_STATIC_ENT("content-encoding", "", 25),
+ MAKE_STATIC_ENT("content-language", "", 26),
+ MAKE_STATIC_ENT("content-length", "", 27),
+ MAKE_STATIC_ENT("content-location", "", 28),
+ MAKE_STATIC_ENT("content-range", "", 29),
+ MAKE_STATIC_ENT("content-type", "", 30),
+ MAKE_STATIC_ENT("cookie", "", 31),
+ MAKE_STATIC_ENT("date", "", 32),
+ MAKE_STATIC_ENT("etag", "", 33),
+ MAKE_STATIC_ENT("expect", "", 34),
+ MAKE_STATIC_ENT("expires", "", 35),
+ MAKE_STATIC_ENT("from", "", 36),
+ MAKE_STATIC_ENT("host", "", 37),
+ MAKE_STATIC_ENT("if-match", "", 38),
+ MAKE_STATIC_ENT("if-modified-since", "", 39),
+ MAKE_STATIC_ENT("if-none-match", "", 40),
+ MAKE_STATIC_ENT("if-range", "", 41),
+ MAKE_STATIC_ENT("if-unmodified-since", "", 42),
+ MAKE_STATIC_ENT("last-modified", "", 43),
+ MAKE_STATIC_ENT("link", "", 44),
+ MAKE_STATIC_ENT("location", "", 45),
+ MAKE_STATIC_ENT("max-forwards", "", 46),
+ MAKE_STATIC_ENT("proxy-authenticate", "", 47),
+ MAKE_STATIC_ENT("proxy-authorization", "", 48),
+ MAKE_STATIC_ENT("range", "", 49),
+ MAKE_STATIC_ENT("referer", "", 50),
+ MAKE_STATIC_ENT("refresh", "", 51),
+ MAKE_STATIC_ENT("retry-after", "", 52),
+ MAKE_STATIC_ENT("server", "", 53),
+ MAKE_STATIC_ENT("set-cookie", "", 54),
+ MAKE_STATIC_ENT("strict-transport-security", "", 55),
+ MAKE_STATIC_ENT("transfer-encoding", "", 56),
+ MAKE_STATIC_ENT("user-agent", "", 57),
+ MAKE_STATIC_ENT("vary", "", 58),
+ MAKE_STATIC_ENT("via", "", 59),
+ MAKE_STATIC_ENT("www-authenticate", "", 60),
};
-/* Index to the position in static_table */
-const size_t static_table_index[] = {
- 38, 43, 44, 10, 11, 47, 48, 49, 50, 51, 52, 53, 54, 55, 14, 60,
- 20, 26, 34, 46, 0, 12, 36, 59, 41, 31, 42, 45, 32, 35, 19, 37,
- 2, 3, 40, 39, 4, 5, 8, 33, 18, 9, 27, 15, 6, 29, 28, 57,
- 16, 13, 21, 22, 30, 56, 24, 23, 25, 17, 7, 1, 58};
-
-const size_t NGHTTP2_STATIC_TABLE_LENGTH =
- sizeof(static_table) / sizeof(static_table[0]);
-
static int memeq(const void *s1, const void *s2, size_t n) {
- const uint8_t *a = (const uint8_t *)s1, *b = (const uint8_t *)s2;
- uint8_t c = 0;
- while (n > 0) {
- c |= (*a++) ^ (*b++);
- --n;
- }
- return c == 0;
+ return memcmp(s1, s2, n) == 0;
}
-static uint32_t hash(const uint8_t *s, size_t n) {
- uint32_t h = 0;
- while (n > 0) {
- h = h * 31 + *s++;
- --n;
+/*
+ * This function was generated by genlibtokenlookup.py. Inspired by
+ * h2o header lookup. https://github.com/h2o/h2o
+ */
+static int lookup_token(const uint8_t *name, size_t namelen) {
+ switch (namelen) {
+ case 2:
+ switch (name[1]) {
+ case 'e':
+ if (lstreq("t", name, 1)) {
+ return NGHTTP2_TOKEN_TE;
+ }
+ break;
+ }
+ break;
+ case 3:
+ switch (name[2]) {
+ case 'a':
+ if (lstreq("vi", name, 2)) {
+ return NGHTTP2_TOKEN_VIA;
+ }
+ break;
+ case 'e':
+ if (lstreq("ag", name, 2)) {
+ return NGHTTP2_TOKEN_AGE;
+ }
+ break;
+ }
+ break;
+ case 4:
+ switch (name[3]) {
+ case 'e':
+ if (lstreq("dat", name, 3)) {
+ return NGHTTP2_TOKEN_DATE;
+ }
+ break;
+ case 'g':
+ if (lstreq("eta", name, 3)) {
+ return NGHTTP2_TOKEN_ETAG;
+ }
+ break;
+ case 'k':
+ if (lstreq("lin", name, 3)) {
+ return NGHTTP2_TOKEN_LINK;
+ }
+ break;
+ case 'm':
+ if (lstreq("fro", name, 3)) {
+ return NGHTTP2_TOKEN_FROM;
+ }
+ break;
+ case 't':
+ if (lstreq("hos", name, 3)) {
+ return NGHTTP2_TOKEN_HOST;
+ }
+ break;
+ case 'y':
+ if (lstreq("var", name, 3)) {
+ return NGHTTP2_TOKEN_VARY;
+ }
+ break;
+ }
+ break;
+ case 5:
+ switch (name[4]) {
+ case 'e':
+ if (lstreq("rang", name, 4)) {
+ return NGHTTP2_TOKEN_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq(":pat", name, 4)) {
+ return NGHTTP2_TOKEN__PATH;
+ }
+ if (lstreq(":pat", name, 4)) {
+ return NGHTTP2_TOKEN__PATH;
+ }
+ break;
+ case 'w':
+ if (lstreq("allo", name, 4)) {
+ return NGHTTP2_TOKEN_ALLOW;
+ }
+ break;
+ }
+ break;
+ case 6:
+ switch (name[5]) {
+ case 'e':
+ if (lstreq("cooki", name, 5)) {
+ return NGHTTP2_TOKEN_COOKIE;
+ }
+ break;
+ case 'r':
+ if (lstreq("serve", name, 5)) {
+ return NGHTTP2_TOKEN_SERVER;
+ }
+ break;
+ case 't':
+ if (lstreq("accep", name, 5)) {
+ return NGHTTP2_TOKEN_ACCEPT;
+ }
+ if (lstreq("expec", name, 5)) {
+ return NGHTTP2_TOKEN_EXPECT;
+ }
+ break;
+ }
+ break;
+ case 7:
+ switch (name[6]) {
+ case 'd':
+ if (lstreq(":metho", name, 6)) {
+ return NGHTTP2_TOKEN__METHOD;
+ }
+ if (lstreq(":metho", name, 6)) {
+ return NGHTTP2_TOKEN__METHOD;
+ }
+ break;
+ case 'e':
+ if (lstreq(":schem", name, 6)) {
+ return NGHTTP2_TOKEN__SCHEME;
+ }
+ if (lstreq(":schem", name, 6)) {
+ return NGHTTP2_TOKEN__SCHEME;
+ }
+ if (lstreq("upgrad", name, 6)) {
+ return NGHTTP2_TOKEN_UPGRADE;
+ }
+ break;
+ case 'h':
+ if (lstreq("refres", name, 6)) {
+ return NGHTTP2_TOKEN_REFRESH;
+ }
+ break;
+ case 'r':
+ if (lstreq("refere", name, 6)) {
+ return NGHTTP2_TOKEN_REFERER;
+ }
+ break;
+ case 's':
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq("expire", name, 6)) {
+ return NGHTTP2_TOKEN_EXPIRES;
+ }
+ break;
+ }
+ break;
+ case 8:
+ switch (name[7]) {
+ case 'e':
+ if (lstreq("if-rang", name, 7)) {
+ return NGHTTP2_TOKEN_IF_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq("if-matc", name, 7)) {
+ return NGHTTP2_TOKEN_IF_MATCH;
+ }
+ break;
+ case 'n':
+ if (lstreq("locatio", name, 7)) {
+ return NGHTTP2_TOKEN_LOCATION;
+ }
+ break;
+ }
+ break;
+ case 10:
+ switch (name[9]) {
+ case 'e':
+ if (lstreq("keep-aliv", name, 9)) {
+ return NGHTTP2_TOKEN_KEEP_ALIVE;
+ }
+ if (lstreq("set-cooki", name, 9)) {
+ return NGHTTP2_TOKEN_SET_COOKIE;
+ }
+ break;
+ case 'n':
+ if (lstreq("connectio", name, 9)) {
+ return NGHTTP2_TOKEN_CONNECTION;
+ }
+ break;
+ case 't':
+ if (lstreq("user-agen", name, 9)) {
+ return NGHTTP2_TOKEN_USER_AGENT;
+ }
+ break;
+ case 'y':
+ if (lstreq(":authorit", name, 9)) {
+ return NGHTTP2_TOKEN__AUTHORITY;
+ }
+ break;
+ }
+ break;
+ case 11:
+ switch (name[10]) {
+ case 'r':
+ if (lstreq("retry-afte", name, 10)) {
+ return NGHTTP2_TOKEN_RETRY_AFTER;
+ }
+ break;
+ }
+ break;
+ case 12:
+ switch (name[11]) {
+ case 'e':
+ if (lstreq("content-typ", name, 11)) {
+ return NGHTTP2_TOKEN_CONTENT_TYPE;
+ }
+ break;
+ case 's':
+ if (lstreq("max-forward", name, 11)) {
+ return NGHTTP2_TOKEN_MAX_FORWARDS;
+ }
+ break;
+ }
+ break;
+ case 13:
+ switch (name[12]) {
+ case 'd':
+ if (lstreq("last-modifie", name, 12)) {
+ return NGHTTP2_TOKEN_LAST_MODIFIED;
+ }
+ break;
+ case 'e':
+ if (lstreq("content-rang", name, 12)) {
+ return NGHTTP2_TOKEN_CONTENT_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq("if-none-matc", name, 12)) {
+ return NGHTTP2_TOKEN_IF_NONE_MATCH;
+ }
+ break;
+ case 'l':
+ if (lstreq("cache-contro", name, 12)) {
+ return NGHTTP2_TOKEN_CACHE_CONTROL;
+ }
+ break;
+ case 'n':
+ if (lstreq("authorizatio", name, 12)) {
+ return NGHTTP2_TOKEN_AUTHORIZATION;
+ }
+ break;
+ case 's':
+ if (lstreq("accept-range", name, 12)) {
+ return NGHTTP2_TOKEN_ACCEPT_RANGES;
+ }
+ break;
+ }
+ break;
+ case 14:
+ switch (name[13]) {
+ case 'h':
+ if (lstreq("content-lengt", name, 13)) {
+ return NGHTTP2_TOKEN_CONTENT_LENGTH;
+ }
+ break;
+ case 't':
+ if (lstreq("accept-charse", name, 13)) {
+ return NGHTTP2_TOKEN_ACCEPT_CHARSET;
+ }
+ break;
+ }
+ break;
+ case 15:
+ switch (name[14]) {
+ case 'e':
+ if (lstreq("accept-languag", name, 14)) {
+ return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
+ }
+ break;
+ case 'g':
+ if (lstreq("accept-encodin", name, 14)) {
+ return NGHTTP2_TOKEN_ACCEPT_ENCODING;
+ }
+ break;
+ }
+ break;
+ case 16:
+ switch (name[15]) {
+ case 'e':
+ if (lstreq("content-languag", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_LANGUAGE;
+ }
+ if (lstreq("www-authenticat", name, 15)) {
+ return NGHTTP2_TOKEN_WWW_AUTHENTICATE;
+ }
+ break;
+ case 'g':
+ if (lstreq("content-encodin", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_ENCODING;
+ }
+ break;
+ case 'n':
+ if (lstreq("content-locatio", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_LOCATION;
+ }
+ if (lstreq("proxy-connectio", name, 15)) {
+ return NGHTTP2_TOKEN_PROXY_CONNECTION;
+ }
+ break;
+ }
+ break;
+ case 17:
+ switch (name[16]) {
+ case 'e':
+ if (lstreq("if-modified-sinc", name, 16)) {
+ return NGHTTP2_TOKEN_IF_MODIFIED_SINCE;
+ }
+ break;
+ case 'g':
+ if (lstreq("transfer-encodin", name, 16)) {
+ return NGHTTP2_TOKEN_TRANSFER_ENCODING;
+ }
+ break;
+ }
+ break;
+ case 18:
+ switch (name[17]) {
+ case 'e':
+ if (lstreq("proxy-authenticat", name, 17)) {
+ return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
+ }
+ break;
+ }
+ break;
+ case 19:
+ switch (name[18]) {
+ case 'e':
+ if (lstreq("if-unmodified-sinc", name, 18)) {
+ return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE;
+ }
+ break;
+ case 'n':
+ if (lstreq("content-dispositio", name, 18)) {
+ return NGHTTP2_TOKEN_CONTENT_DISPOSITION;
+ }
+ if (lstreq("proxy-authorizatio", name, 18)) {
+ return NGHTTP2_TOKEN_PROXY_AUTHORIZATION;
+ }
+ break;
+ }
+ break;
+ case 25:
+ switch (name[24]) {
+ case 'y':
+ if (lstreq("strict-transport-securit", name, 24)) {
+ return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
+ }
+ break;
+ }
+ break;
+ case 27:
+ switch (name[26]) {
+ case 'n':
+ if (lstreq("access-control-allow-origi", name, 26)) {
+ return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
+ }
+ break;
+ }
+ break;
}
- return h;
+ return -1;
}
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
size_t namelen, uint8_t *value, size_t valuelen,
- uint32_t name_hash, uint32_t value_hash,
- nghttp2_mem *mem) {
+ int token, nghttp2_mem *mem) {
int rv = 0;
/* Since nghttp2_hd_entry is used for indexing, ent->nv.flags always
@@ -152,10 +506,11 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
if ((flags & NGHTTP2_HD_FLAG_NAME_ALLOC) &&
(flags & NGHTTP2_HD_FLAG_NAME_GIFT) == 0) {
if (namelen == 0) {
- /* We should not allow empty header field name */
- ent->nv.name = NULL;
+ flags &= ~NGHTTP2_HD_FLAG_NAME_ALLOC;
+ ent->nv.name = (uint8_t *)"";
} else {
- ent->nv.name = (uint8_t *)nghttp2_memdup(name, namelen, mem);
+ /* copy including terminating NULL byte */
+ ent->nv.name = (uint8_t *)nghttp2_memdup(name, namelen + 1, mem);
if (ent->nv.name == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
@@ -167,9 +522,11 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
if ((flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) &&
(flags & NGHTTP2_HD_FLAG_VALUE_GIFT) == 0) {
if (valuelen == 0) {
- ent->nv.value = NULL;
+ flags &= ~NGHTTP2_HD_FLAG_VALUE_ALLOC;
+ ent->nv.value = (uint8_t *)"";
} else {
- ent->nv.value = (uint8_t *)nghttp2_memdup(value, valuelen, mem);
+ /* copy including terminating NULL byte */
+ ent->nv.value = (uint8_t *)nghttp2_memdup(value, valuelen + 1, mem);
if (ent->nv.value == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail2;
@@ -180,12 +537,10 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
}
ent->nv.namelen = namelen;
ent->nv.valuelen = valuelen;
+ ent->token = token;
ent->ref = 1;
ent->flags = flags;
- ent->name_hash = name_hash;
- ent->value_hash = value_hash;
-
return 0;
fail2:
@@ -403,25 +758,23 @@ static size_t entry_room(size_t namelen, size_t valuelen) {
return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen;
}
-static int emit_indexed_header(nghttp2_nv *nv_out, nghttp2_hd_entry *ent) {
- DEBUGF(fprintf(stderr, "inflatehd: header emission: "));
- DEBUGF(fwrite(ent->nv.name, ent->nv.namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(ent->nv.value, ent->nv.valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+static int emit_indexed_header(nghttp2_nv *nv_out, int *token_out,
+ nghttp2_hd_entry *ent) {
+ DEBUGF(fprintf(stderr, "inflatehd: header emission: %s: %s\n", ent->nv.name,
+ ent->nv.value));
/* ent->ref may be 0. This happens if the encoder emits literal
block larger than header table capacity with indexing. */
*nv_out = ent->nv;
+ *token_out = ent->token;
return 0;
}
-static int emit_literal_header(nghttp2_nv *nv_out, nghttp2_nv *nv) {
- DEBUGF(fprintf(stderr, "inflatehd: header emission: "));
- DEBUGF(fwrite(nv->name, nv->namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(nv->value, nv->valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+static int emit_literal_header(nghttp2_nv *nv_out, int *token_out,
+ nghttp2_nv *nv) {
+ DEBUGF(fprintf(stderr, "inflatehd: header emission: %s: %s\n", nv->name,
+ nv->value));
*nv_out = *nv;
+ *token_out = lookup_token(nv->name, nv->namelen);
return 0;
}
@@ -642,38 +995,39 @@ static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
return rv;
}
-static uint8_t pack_first_byte(int inc_indexing, int no_index) {
- if (inc_indexing) {
+static uint8_t pack_first_byte(int indexing_mode) {
+ switch (indexing_mode) {
+ case NGHTTP2_HD_WITH_INDEXING:
return 0x40u;
- }
-
- if (no_index) {
+ case NGHTTP2_HD_WITHOUT_INDEXING:
+ return 0;
+ case NGHTTP2_HD_NEVER_INDEXING:
return 0x10u;
+ default:
+ assert(0);
}
-
+ /* This is required to compile with android NDK r10d +
+ --enable-werror */
return 0;
}
static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
- const nghttp2_nv *nv, int inc_indexing) {
+ const nghttp2_nv *nv, int indexing_mode) {
int rv;
uint8_t *bufp;
size_t blocklen;
uint8_t sb[16];
size_t prefixlen;
- int no_index;
- no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
-
- if (inc_indexing) {
+ if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
prefixlen = 6;
} else {
prefixlen = 4;
}
DEBUGF(fprintf(stderr, "deflatehd: emit indname index=%zu, valuelen=%zu, "
- "indexing=%d, no_index=%d\n",
- idx, nv->valuelen, inc_indexing, no_index));
+ "indexing_mode=%d\n",
+ idx, nv->valuelen, indexing_mode));
blocklen = count_encoded_length(idx + 1, prefixlen);
@@ -683,7 +1037,7 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
bufp = sb;
- *bufp = pack_first_byte(inc_indexing, no_index);
+ *bufp = pack_first_byte(indexing_mode);
encode_length(bufp, idx + 1, prefixlen);
@@ -701,17 +1055,14 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
}
static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
- int inc_indexing) {
+ int indexing_mode) {
int rv;
- int no_index;
-
- no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
DEBUGF(fprintf(stderr, "deflatehd: emit newname namelen=%zu, valuelen=%zu, "
- "indexing=%d, no_index=%d\n",
- nv->namelen, nv->valuelen, inc_indexing, no_index));
+ "indexing_mode=%d\n",
+ nv->namelen, nv->valuelen, indexing_mode));
- rv = nghttp2_bufs_addb(bufs, pack_first_byte(inc_indexing, no_index));
+ rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
if (rv != 0) {
return rv;
}
@@ -731,8 +1082,7 @@ static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
const nghttp2_nv *nv,
- uint32_t name_hash,
- uint32_t value_hash,
+ int token,
uint8_t entry_flags) {
int rv;
nghttp2_hd_entry *new_ent;
@@ -750,11 +1100,9 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
- DEBUGF(fprintf(stderr, "hpack: remove item from header table: "));
- DEBUGF(fwrite(ent->nv.name, ent->nv.namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(ent->nv.value, ent->nv.valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+ DEBUGF(fprintf(stderr, "hpack: remove item from header table: %s: %s\n",
+ ent->nv.name, ent->nv.value));
+
hd_ringbuf_pop_back(&context->hd_table);
if (--ent->ref == 0) {
nghttp2_hd_entry_free(ent, mem);
@@ -768,8 +1116,7 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
}
rv = nghttp2_hd_entry_init(new_ent, entry_flags, nv->name, nv->namelen,
- nv->value, nv->valuelen, name_hash, value_hash,
- mem);
+ nv->value, nv->valuelen, token, mem);
if (rv != 0) {
nghttp2_mem_free(mem, new_ent);
return NULL;
@@ -810,11 +1157,15 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
}
static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) {
- return a->namelen == b->namelen && memeq(a->name, b->name, a->namelen);
+ return a->namelen == b->namelen &&
+ a->name[a->namelen - 1] == b->name[a->namelen - 1] &&
+ memeq(a->name, b->name, a->namelen);
}
static int value_eq(const nghttp2_nv *a, const nghttp2_nv *b) {
- return a->valuelen == b->valuelen && memeq(a->value, b->value, a->valuelen);
+ return a->valuelen == b->valuelen &&
+ a->value[a->valuelen - 1] == b->value[a->valuelen - 1] &&
+ memeq(a->value, b->value, a->valuelen);
}
typedef struct {
@@ -823,61 +1174,54 @@ typedef struct {
uint8_t name_value_match;
} search_result;
+static search_result search_static_table(const nghttp2_nv *nv, int token,
+ int indexing_mode) {
+ search_result res = {token, 0};
+ int i;
+
+ if (indexing_mode == NGHTTP2_HD_NEVER_INDEXING) {
+ return res;
+ }
+
+ for (i = token;
+ i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token;
+ ++i) {
+ if (value_eq(&static_table[i].nv, nv)) {
+ res.index = i;
+ res.name_value_match = 1;
+ return res;
+ }
+ }
+ return res;
+}
+
static search_result search_hd_table(nghttp2_hd_context *context,
- const nghttp2_nv *nv, uint32_t name_hash,
- uint32_t value_hash) {
- ssize_t left = -1, right = (ssize_t)STATIC_TABLE_LENGTH;
+ const nghttp2_nv *nv, int token,
+ int indexing_mode) {
search_result res = {-1, 0};
size_t i;
- int use_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) == 0;
-
- /* Search dynamic table first, so that we can find recently used
- entry first */
- if (use_index) {
- for (i = 0; i < context->hd_table.len; ++i) {
- nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, i);
- if (ent->name_hash != name_hash || !name_eq(&ent->nv, nv)) {
- continue;
- }
- if (res.index == -1) {
- res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
- }
-
- if (ent->value_hash == value_hash && value_eq(&ent->nv, nv)) {
- res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
- res.name_value_match = 1;
- return res;
- }
+ if (token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
+ res = search_static_table(nv, token, indexing_mode);
+ if (res.name_value_match) {
+ return res;
}
}
- while (right - left > 1) {
- ssize_t mid = (left + right) / 2;
- nghttp2_hd_entry *ent = &static_table[mid].ent;
- if (ent->name_hash < name_hash) {
- left = mid;
- } else {
- right = mid;
+ for (i = 0; i < context->hd_table.len; ++i) {
+ nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, i);
+ if (ent->token != token || (token == -1 && !name_eq(&ent->nv, nv))) {
+ continue;
}
- }
- for (i = right; i < STATIC_TABLE_LENGTH; ++i) {
- nghttp2_hd_entry *ent = &static_table[i].ent;
- if (ent->name_hash != name_hash) {
- break;
+ if (res.index == -1) {
+ res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
}
- if (name_eq(&ent->nv, nv)) {
- if (res.index == -1) {
- res.index = (ssize_t)(static_table[i].index);
- }
- if (use_index && ent->value_hash == value_hash &&
- value_eq(&ent->nv, nv)) {
- res.index = (ssize_t)(static_table[i].index);
- res.name_value_match = 1;
- return res;
- }
+ if (indexing_mode != NGHTTP2_HD_NEVER_INDEXING && value_eq(&ent->nv, nv)) {
+ res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
+ res.name_value_match = 1;
+ return res;
}
}
@@ -940,29 +1284,23 @@ nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context,
return hd_ringbuf_get(&context->hd_table,
idx - NGHTTP2_STATIC_TABLE_LENGTH);
} else {
- return &static_table[static_table_index[idx]].ent;
+ return &static_table[idx];
}
}
-#define name_match(NV, NAME) \
- (nv->namelen == sizeof(NAME) - 1 && memeq(nv->name, NAME, sizeof(NAME) - 1))
-
-static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
- const nghttp2_nv *nv) {
- if ((nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) ||
+static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
+ const nghttp2_nv *nv, int token) {
+ if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE ||
+ token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG ||
+ token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE ||
+ token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION ||
+ token == NGHTTP2_TOKEN_SET_COOKIE ||
entry_room(nv->namelen, nv->valuelen) >
deflater->ctx.hd_table_bufsize_max * 3 / 4) {
- return 0;
+ return NGHTTP2_HD_WITHOUT_INDEXING;
}
-#ifdef NGHTTP2_XHD
- return !name_match(nv, NGHTTP2_XHD);
-#else /* !NGHTTP2_XHD */
- return !name_match(nv, ":path") && !name_match(nv, "content-length") &&
- !name_match(nv, "set-cookie") && !name_match(nv, "etag") &&
- !name_match(nv, "if-modified-since") &&
- !name_match(nv, "if-none-match") && !name_match(nv, "location") &&
- !name_match(nv, "age");
-#endif /* !NGHTTP2_XHD */
+
+ return NGHTTP2_HD_WITH_INDEXING;
}
static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
@@ -970,20 +1308,28 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
int rv;
search_result res;
ssize_t idx;
- int incidx = 0;
- uint32_t name_hash = hash(nv->name, nv->namelen);
- uint32_t value_hash = hash(nv->value, nv->valuelen);
+ int indexing_mode;
+ int token;
nghttp2_mem *mem;
- DEBUGF(fprintf(stderr, "deflatehd: deflating "));
- DEBUGF(fwrite(nv->name, nv->namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(nv->value, nv->valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+ DEBUGF(fprintf(stderr, "deflatehd: deflating %s: %s\n", nv->name, nv->value));
mem = deflater->ctx.mem;
- res = search_hd_table(&deflater->ctx, nv, name_hash, value_hash);
+ token = lookup_token(nv->name, nv->namelen);
+
+ /* Don't index authorization header field since it may contain low
+ entropy secret data (e.g., id/password). Also cookie header
+ field with less than 20 bytes value is also never indexed. This
+ is the same criteria used in Firefox codebase. */
+ indexing_mode =
+ token == NGHTTP2_TOKEN_AUTHORIZATION ||
+ (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) ||
+ (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
+ ? NGHTTP2_HD_NEVER_INDEXING
+ : hd_deflate_decide_indexing(deflater, nv, token);
+
+ res = search_hd_table(&deflater->ctx, nv, token, indexing_mode);
idx = res.index;
@@ -1003,19 +1349,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
DEBUGF(fprintf(stderr, "deflatehd: name match index=%zd\n", res.index));
}
- if (hd_deflate_should_indexing(deflater, nv)) {
+ if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
nghttp2_hd_entry *new_ent;
if (idx != -1 && idx < (ssize_t)NGHTTP2_STATIC_TABLE_LENGTH) {
nghttp2_nv nv_indname;
nv_indname = *nv;
nv_indname.name = nghttp2_hd_table_get(&deflater->ctx, idx)->nv.name;
- new_ent =
- add_hd_table_incremental(&deflater->ctx, &nv_indname, name_hash,
- value_hash, NGHTTP2_HD_FLAG_VALUE_ALLOC);
+ new_ent = add_hd_table_incremental(&deflater->ctx, &nv_indname, token,
+ NGHTTP2_HD_FLAG_VALUE_ALLOC);
} else {
- new_ent = add_hd_table_incremental(
- &deflater->ctx, nv, name_hash, value_hash,
- NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC);
+ new_ent = add_hd_table_incremental(&deflater->ctx, nv, token,
+ NGHTTP2_HD_FLAG_NAME_ALLOC |
+ NGHTTP2_HD_FLAG_VALUE_ALLOC);
}
if (!new_ent) {
return NGHTTP2_ERR_HEADER_COMP;
@@ -1024,12 +1369,11 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
nghttp2_hd_entry_free(new_ent, mem);
nghttp2_mem_free(mem, new_ent);
}
- incidx = 1;
}
if (idx == -1) {
- rv = emit_newname_block(bufs, nv, incidx);
+ rv = emit_newname_block(bufs, nv, indexing_mode);
} else {
- rv = emit_indname_block(bufs, idx, nv, incidx);
+ rv = emit_indname_block(bufs, idx, nv, indexing_mode);
}
if (rv != 0) {
return rv;
@@ -1313,10 +1657,10 @@ static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater,
* Out of memory
*/
static int hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
- nghttp2_nv *nv_out) {
+ nghttp2_nv *nv_out, int *token_out) {
nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
- emit_indexed_header(nv_out, ent);
+ emit_indexed_header(nv_out, token_out, ent);
return 0;
}
@@ -1337,18 +1681,24 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
return NGHTTP2_ERR_NOMEM;
}
+ nghttp2_bufs_reset(&inflater->nvbufs);
+
buflen = rv;
if (value_only) {
+ /* we don't use this value, so no need to NULL-terminate */
nv->name = NULL;
nv->namelen = 0;
+
+ nv->value = buf;
+ nv->valuelen = buflen - 1;
} else {
nv->name = buf;
nv->namelen = inflater->newnamelen;
- }
- nv->value = buf + nv->namelen;
- nv->valuelen = buflen - nv->namelen;
+ nv->value = buf + nv->namelen + 1;
+ nv->valuelen = buflen - nv->namelen - 2;
+ }
return 0;
}
@@ -1360,15 +1710,19 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
pbuf = &inflater->nvbufs.head->buf;
if (value_only) {
+ /* we don't use this value, so no need to NULL-terminate */
nv->name = NULL;
nv->namelen = 0;
+
+ nv->value = pbuf->pos;
+ nv->valuelen = nghttp2_buf_len(pbuf) - 1;
} else {
nv->name = pbuf->pos;
nv->namelen = inflater->newnamelen;
- }
- nv->value = pbuf->pos + nv->namelen;
- nv->valuelen = nghttp2_buf_len(pbuf) - nv->namelen;
+ nv->value = pbuf->pos + nv->namelen + 1;
+ nv->valuelen = nghttp2_buf_len(pbuf) - nv->namelen - 2;
+ }
/* Resetting does not change the content of first buffer */
nghttp2_bufs_reset(&inflater->nvbufs);
@@ -1376,6 +1730,42 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
return 0;
}
+static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
+ nghttp2_nv *nv,
+ nghttp2_hd_entry *ent_name) {
+ size_t rv;
+ size_t buflen;
+ uint8_t *buf;
+ nghttp2_mem *mem;
+
+ mem = inflater->ctx.mem;
+
+ /* Allocate buffer including name in ent_name, plus terminating
+ NULL. */
+ buflen = ent_name->nv.namelen + 1 + nghttp2_bufs_len(&inflater->nvbufs);
+
+ buf = (uint8_t *)nghttp2_mem_malloc(mem, buflen);
+ if (buf == NULL) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+
+ /* Copy including terminal NULL */
+ memcpy(buf, ent_name->nv.name, ent_name->nv.namelen + 1);
+ rv = nghttp2_bufs_remove_copy(&inflater->nvbufs,
+ buf + ent_name->nv.namelen + 1);
+ assert(ent_name->nv.namelen + 1 + rv == buflen);
+
+ nghttp2_bufs_reset(&inflater->nvbufs);
+
+ nv->name = buf;
+ nv->namelen = ent_name->nv.namelen;
+
+ nv->value = buf + nv->namelen + 1;
+ nv->valuelen = buflen - nv->namelen - 2;
+
+ return 0;
+}
+
/*
* Finalize literal header representation - new name- reception. If
* header is emitted, |*nv_out| is filled with that value and 0 is
@@ -1388,7 +1778,7 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
* Out of memory
*/
static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
- nghttp2_nv *nv_out) {
+ nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv;
nghttp2_mem *mem;
@@ -1415,12 +1805,11 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
management. */
ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT;
- new_ent =
- add_hd_table_incremental(&inflater->ctx, &nv, hash(nv.name, nv.namelen),
- hash(nv.value, nv.valuelen), ent_flags);
+ new_ent = add_hd_table_incremental(
+ &inflater->ctx, &nv, lookup_token(nv.name, nv.namelen), ent_flags);
if (new_ent) {
- emit_indexed_header(nv_out, new_ent);
+ emit_indexed_header(nv_out, token_out, new_ent);
inflater->ent_keep = new_ent;
return 0;
@@ -1431,7 +1820,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
return NGHTTP2_ERR_NOMEM;
}
- emit_literal_header(nv_out, &nv);
+ emit_literal_header(nv_out, token_out, &nv);
if (nv.name != inflater->nvbufs.head->buf.pos) {
inflater->nv_keep = nv.name;
@@ -1452,7 +1841,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
* Out of memory
*/
static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
- nghttp2_nv *nv_out) {
+ nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv;
nghttp2_hd_entry *ent_name;
@@ -1460,11 +1849,6 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
mem = inflater->ctx.mem;
- rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */);
- if (rv != 0) {
- return NGHTTP2_ERR_NOMEM;
- }
-
if (inflater->no_index) {
nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
} else {
@@ -1473,34 +1857,36 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
ent_name = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
- nv.name = ent_name->nv.name;
- nv.namelen = ent_name->nv.namelen;
-
if (inflater->index_required) {
nghttp2_hd_entry *new_ent;
uint8_t ent_flags;
- int static_name;
- ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT;
- static_name = inflater->index < NGHTTP2_STATIC_TABLE_LENGTH;
+ if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) {
+ /* We don't copy name in static table */
+ rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */);
+ if (rv != 0) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+ nv.name = ent_name->nv.name;
+ nv.namelen = ent_name->nv.namelen;
- if (!static_name) {
- ent_flags |= NGHTTP2_HD_FLAG_NAME_ALLOC;
- /* For entry in static table, we must not touch ref, because it
- is shared by threads */
- ++ent_name->ref;
+ ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT;
+ } else {
+ rv = hd_inflate_remove_bufs_with_name(inflater, &nv, ent_name);
+ if (rv != 0) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+ /* nv->name and nv->value are in the same buffer. */
+ ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT;
}
- new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->name_hash,
- hash(nv.value, nv.valuelen), ent_flags);
+ new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token,
+ ent_flags);
- if (!static_name && --ent_name->ref == 0) {
- nghttp2_hd_entry_free(ent_name, mem);
- nghttp2_mem_free(mem, ent_name);
- }
+ /* At this point, ent_name might be deleted. */
if (new_ent) {
- emit_indexed_header(nv_out, new_ent);
+ emit_indexed_header(nv_out, token_out, new_ent);
inflater->ent_keep = new_ent;
@@ -1512,7 +1898,15 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
return NGHTTP2_ERR_NOMEM;
}
- emit_literal_header(nv_out, &nv);
+ rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */);
+ if (rv != 0) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+
+ nv.name = ent_name->nv.name;
+ nv.namelen = ent_name->nv.namelen;
+
+ emit_literal_header(nv_out, token_out, &nv);
if (nv.value != inflater->nvbufs.head->buf.pos) {
inflater->nv_keep = nv.value;
@@ -1524,10 +1918,21 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
int *inflate_flags, uint8_t *in, size_t inlen,
int in_final) {
+ int token;
+
+ return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, &token, in,
+ inlen, in_final);
+}
+
+ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
+ nghttp2_nv *nv_out, int *inflate_flags,
+ int *token_out, uint8_t *in, size_t inlen,
+ int in_final) {
ssize_t rv = 0;
uint8_t *first = in;
uint8_t *last = in + inlen;
int rfin = 0;
+ int busy = 0;
if (inflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP;
@@ -1535,8 +1940,10 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
DEBUGF(fprintf(stderr, "inflatehd: start state=%d\n", inflater->state));
hd_inflate_keep_free(inflater);
+ *token_out = -1;
*inflate_flags = NGHTTP2_HD_INFLATE_NONE;
- for (; in != last;) {
+ for (; in != last || busy;) {
+ busy = 0;
switch (inflater->state) {
case NGHTTP2_HD_STATE_OPCODE:
if ((*in & 0xe0u) == 0x20u) {
@@ -1620,7 +2027,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->index = inflater->left;
--inflater->index;
- rv = hd_inflate_commit_indexed(inflater, nv_out);
+ rv = hd_inflate_commit_indexed(inflater, nv_out, token_out);
if (rv < 0) {
goto fail;
}
@@ -1688,6 +2095,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs);
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
break;
@@ -1709,6 +2121,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs);
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
break;
@@ -1734,19 +2151,6 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
}
DEBUGF(fprintf(stderr, "inflatehd: valuelen=%zu\n", inflater->left));
- if (inflater->left == 0) {
- if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
- } else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
- }
- if (rv != 0) {
- goto fail;
- }
- inflater->state = NGHTTP2_HD_STATE_OPCODE;
- *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
- return (ssize_t)(in - first);
- }
if (inflater->huffman_encoded) {
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
@@ -1755,6 +2159,9 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
} else {
inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
}
+
+ busy = 1;
+
break;
case NGHTTP2_HD_STATE_READ_VALUEHUFF:
rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last);
@@ -1773,10 +2180,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
goto almost_ok;
}
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
+ rv = hd_inflate_commit_newname(inflater, nv_out, token_out);
} else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
+ rv = hd_inflate_commit_indname(inflater, nv_out, token_out);
}
if (rv != 0) {
@@ -1805,10 +2217,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
goto almost_ok;
}
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
+ rv = hd_inflate_commit_newname(inflater, nv_out, token_out);
} else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
+ rv = hd_inflate_commit_indname(inflater, nv_out, token_out);
}
if (rv != 0) {
@@ -1904,14 +2321,14 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
}
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
- nghttp2_nv *nv, int inc_indexing) {
+ nghttp2_nv *nv, int indexing_mode) {
- return emit_indname_block(bufs, idx, nv, inc_indexing);
+ return emit_indname_block(bufs, idx, nv, indexing_mode);
}
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
- int inc_indexing) {
- return emit_newname_block(bufs, nv, inc_indexing);
+ int indexing_mode) {
+ return emit_newname_block(bufs, nv, indexing_mode);
}
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {