diff options
-rw-r--r-- | epan/nghttp2/nghttp2_buf.c | 16 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_buf.h | 21 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.c | 348 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.h | 21 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd_huffman.c | 22 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd_huffman.h | 3 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_helper.c | 2 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_helper.h | 7 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2ver.h | 4 |
9 files changed, 292 insertions, 152 deletions
diff --git a/epan/nghttp2/nghttp2_buf.c b/epan/nghttp2/nghttp2_buf.c index 6bba48cc20..f6018bca46 100644 --- a/epan/nghttp2/nghttp2_buf.c +++ b/epan/nghttp2/nghttp2_buf.c @@ -244,9 +244,9 @@ void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) { } } -ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs) { +size_t nghttp2_bufs_len(nghttp2_bufs *bufs) { nghttp2_buf_chain *ci; - ssize_t len; + size_t len; len = 0; for (ci = bufs->head; ci; ci = ci->next) { @@ -256,10 +256,10 @@ ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs) { return len; } -static ssize_t bufs_avail(nghttp2_bufs *bufs) { - return (ssize_t)(nghttp2_buf_avail(&bufs->cur->buf) + - (bufs->chunk_length - bufs->offset) * - (bufs->max_chunk - bufs->chunk_used)); +static size_t bufs_avail(nghttp2_bufs *bufs) { + return nghttp2_buf_avail(&bufs->cur->buf) + + (bufs->chunk_length - bufs->offset) * + (bufs->max_chunk - bufs->chunk_used); } static int bufs_alloc_chain(nghttp2_bufs *bufs) { @@ -301,7 +301,7 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { nghttp2_buf *buf; const uint8_t *p; - if (bufs_avail(bufs) < (ssize_t)len) { + if (bufs_avail(bufs) < len) { return NGHTTP2_ERR_BUFFER_ERROR; } @@ -310,7 +310,7 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { while (len) { buf = &bufs->cur->buf; - nwrite = nghttp2_min((size_t)nghttp2_buf_avail(buf), len); + nwrite = nghttp2_min(nghttp2_buf_avail(buf), len); if (nwrite == 0) { rv = bufs_alloc_chain(bufs); if (rv != 0) { diff --git a/epan/nghttp2/nghttp2_buf.h b/epan/nghttp2/nghttp2_buf.h index a84dc7bea2..072e835ec1 100644 --- a/epan/nghttp2/nghttp2_buf.h +++ b/epan/nghttp2/nghttp2_buf.h @@ -51,13 +51,13 @@ typedef struct { uint8_t *mark; } nghttp2_buf; -#define nghttp2_buf_len(BUF) ((ssize_t)((BUF)->last - (BUF)->pos)) -#define nghttp2_buf_avail(BUF) ((ssize_t)((BUF)->end - (BUF)->last)) -#define nghttp2_buf_mark_avail(BUF) ((ssize_t)((BUF)->mark - (BUF)->last)) -#define nghttp2_buf_cap(BUF) ((ssize_t)((BUF)->end - (BUF)->begin)) +#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos)) +#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last)) +#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last)) +#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin)) -#define nghttp2_buf_pos_offset(BUF) ((ssize_t)((BUF)->pos - (BUF)->begin)) -#define nghttp2_buf_last_offset(BUF) ((ssize_t)((BUF)->last - (BUF)->begin)) +#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin)) +#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin)) #define nghttp2_buf_shift_right(BUF, AMT) \ do { \ @@ -300,12 +300,15 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b); #define nghttp2_bufs_fast_orb(BUFS, B) \ do { \ - *(BUFS)->cur->buf.last++ |= B; \ + uint8_t **p = &(BUFS)->cur->buf.last; \ + **p = (uint8_t)(**p | (B)); \ + ++(*p); \ } while (0) #define nghttp2_bufs_fast_orb_hold(BUFS, B) \ do { \ - *(BUFS)->cur->buf.last |= B; \ + uint8_t *p = (BUFS)->cur->buf.last; \ + *p = (uint8_t)(*p | (B)); \ } while (0) /* @@ -380,6 +383,6 @@ int nghttp2_bufs_next_present(nghttp2_bufs *bufs); /* * Returns the buffer length of |bufs|. */ -ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs); +size_t nghttp2_bufs_len(nghttp2_bufs *bufs); #endif /* NGHTTP2_BUF_H */ diff --git a/epan/nghttp2/nghttp2_hd.c b/epan/nghttp2/nghttp2_hd.c index 326ae723a2..d08e5c411c 100644 --- a/epan/nghttp2/nghttp2_hd.c +++ b/epan/nghttp2/nghttp2_hd.c @@ -32,10 +32,10 @@ #include "nghttp2_int.h" /* Make scalar initialization form of nghttp2_hd_entry */ -#define MAKE_STATIC_ENT(N, V, T) \ +#define MAKE_STATIC_ENT(N, V, T, H) \ { \ { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \ - , (T), 1, NGHTTP2_HD_FLAG_NONE \ + , NULL, 0, (H), (T), 1, NGHTTP2_HD_FLAG_NONE \ } /* Generated by mkstatictbl.py */ @@ -43,67 +43,67 @@ 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), + MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), + MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), + MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), + MAKE_STATIC_ENT(":path", "/", 3, 3292848686u), + MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u), + MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u), + MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u), + MAKE_STATIC_ENT(":status", "200", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "204", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "206", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "304", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "400", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "404", 7, 4000288983u), + MAKE_STATIC_ENT(":status", "500", 7, 4000288983u), + MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u), + MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u), + MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u), + MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u), + MAKE_STATIC_ENT("accept", "", 18, 136609321u), + MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u), + MAKE_STATIC_ENT("age", "", 20, 742476188u), + MAKE_STATIC_ENT("allow", "", 21, 2930878514u), + MAKE_STATIC_ENT("authorization", "", 22, 2436257726u), + MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u), + MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u), + MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u), + MAKE_STATIC_ENT("content-language", "", 26, 24973587u), + MAKE_STATIC_ENT("content-length", "", 27, 1308181789u), + MAKE_STATIC_ENT("content-location", "", 28, 2302364718u), + MAKE_STATIC_ENT("content-range", "", 29, 3555523146u), + MAKE_STATIC_ENT("content-type", "", 30, 4244048277u), + MAKE_STATIC_ENT("cookie", "", 31, 2007449791u), + MAKE_STATIC_ENT("date", "", 32, 3564297305u), + MAKE_STATIC_ENT("etag", "", 33, 113792960u), + MAKE_STATIC_ENT("expect", "", 34, 2530896728u), + MAKE_STATIC_ENT("expires", "", 35, 1049544579u), + MAKE_STATIC_ENT("from", "", 36, 2513272949u), + MAKE_STATIC_ENT("host", "", 37, 2952701295u), + MAKE_STATIC_ENT("if-match", "", 38, 3597694698u), + MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u), + MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u), + MAKE_STATIC_ENT("if-range", "", 41, 2340978238u), + MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u), + MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u), + MAKE_STATIC_ENT("link", "", 44, 232457833u), + MAKE_STATIC_ENT("location", "", 45, 200649126u), + MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u), + MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u), + MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u), + MAKE_STATIC_ENT("range", "", 49, 4208725202u), + MAKE_STATIC_ENT("referer", "", 50, 3969579366u), + MAKE_STATIC_ENT("refresh", "", 51, 3572655668u), + MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u), + MAKE_STATIC_ENT("server", "", 53, 1085029842u), + MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u), + MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u), + MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u), + MAKE_STATIC_ENT("user-agent", "", 57, 606444526u), + MAKE_STATIC_ENT("vary", "", 58, 1085005381u), + MAKE_STATIC_ENT("via", "", 59, 1762798611u), + MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u), }; static int memeq(const void *s1, const void *s2, size_t n) { @@ -506,7 +506,7 @@ 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) { - flags &= ~NGHTTP2_HD_FLAG_NAME_ALLOC; + flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_NAME_ALLOC); ent->nv.name = (uint8_t *)""; } else { /* copy including terminating NULL byte */ @@ -522,7 +522,7 @@ 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) { - flags &= ~NGHTTP2_HD_FLAG_VALUE_ALLOC; + flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_VALUE_ALLOC); ent->nv.value = (uint8_t *)""; } else { /* copy including terminating NULL byte */ @@ -540,6 +540,8 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name, ent->token = token; ent->ref = 1; ent->flags = flags; + ent->next = NULL; + ent->hash = 0; return 0; @@ -562,6 +564,97 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem) { } } +static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) { + return a->namelen == b->namelen && 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); +} + +static uint32_t name_hash(const nghttp2_nv *nv) { + /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */ + uint32_t h = 2166136261; + size_t i; + + for (i = 0; i < nv->namelen; ++i) { + h ^= nv->name[i]; + h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); + } + + return h; +} + +static void hd_map_init(nghttp2_hd_map *map) { + memset(map, 0, sizeof(nghttp2_hd_map)); +} + +static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { + nghttp2_hd_entry **bucket; + + bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; + + if (*bucket == NULL) { + *bucket = ent; + return; + } + + /* lower index is linked near the root */ + ent->next = *bucket; + *bucket = ent; +} + +static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, + const nghttp2_nv *nv, int token, + uint32_t hash) { + nghttp2_hd_entry *p; + nghttp2_hd_entry *res = NULL; + + *exact_match = 0; + + for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) { + if (hash != p->hash || token != p->token || + (token == -1 && !name_eq(&p->nv, nv))) { + continue; + } + if (!res) { + res = p; + } + if (value_eq(&p->nv, nv)) { + res = p; + *exact_match = 1; + break; + } + } + + return res; +} + +static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { + nghttp2_hd_entry **bucket; + nghttp2_hd_entry *p; + + bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; + + if (*bucket == NULL) { + return; + } + + if (*bucket == ent) { + *bucket = ent->next; + ent->next = NULL; + return; + } + + for (p = *bucket; p; p = p->next) { + if (p->next == ent) { + p->next = ent->next; + ent->next = NULL; + return; + } + } +} + static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, nghttp2_mem *mem) { size_t size; @@ -656,6 +749,8 @@ static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) { } context->hd_table_bufsize = 0; + context->next_seq = 0; + return 0; } @@ -677,6 +772,8 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, return rv; } + hd_map_init(&deflater->map); + if (deflate_hd_table_bufsize_max < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) { deflater->notify_table_size_change = 1; deflater->ctx.hd_table_bufsize_max = deflate_hd_table_bufsize_max; @@ -780,7 +877,7 @@ static int emit_literal_header(nghttp2_nv *nv_out, int *token_out, } static size_t count_encoded_length(size_t n, size_t prefix) { - size_t k = (1 << prefix) - 1; + size_t k = (size_t)((1 << prefix) - 1); size_t len = 0; if (n < k) { @@ -797,21 +894,23 @@ static size_t count_encoded_length(size_t n, size_t prefix) { } static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) { - size_t k = (1 << prefix) - 1; + size_t k = (size_t)((1 << prefix) - 1); uint8_t *begin = buf; - *buf &= ~k; + *buf = (uint8_t)(*buf & ~k); if (n < k) { - *buf |= n; + *buf = (uint8_t)(*buf | n); return 1; } - *buf++ |= k; + *buf = (uint8_t)(*buf | k); + ++buf; + n -= k; for (; n >= 128; n >>= 7) { - *buf++ = (1 << 7) | (n & 0x7f); + *buf++ = (uint8_t)((1 << 7) | (n & 0x7f)); } *buf++ = (uint8_t)n; @@ -839,7 +938,7 @@ static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) { static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *final, uint32_t initial, size_t shift, uint8_t *in, uint8_t *last, size_t prefix) { - uint32_t k = (1 << prefix) - 1; + uint32_t k = (uint8_t)((1 << prefix) - 1); uint32_t n = initial; uint8_t *start = in; @@ -1081,10 +1180,10 @@ static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv, return 0; } -static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context, - const nghttp2_nv *nv, - int token, - uint8_t entry_flags) { +static nghttp2_hd_entry * +add_hd_table_incremental(nghttp2_hd_context *context, const nghttp2_nv *nv, + int token, uint8_t entry_flags, nghttp2_hd_map *map, + uint32_t hash) { int rv; nghttp2_hd_entry *new_ent; size_t room; @@ -1105,6 +1204,9 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context, ent->nv.name, ent->nv.value)); hd_ringbuf_pop_back(&context->hd_table); + if (map) { + hd_map_remove(map, ent); + } if (--ent->ref == 0) { nghttp2_hd_entry_free(ent, mem); nghttp2_mem_free(mem, ent); @@ -1152,19 +1254,21 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context, return NULL; } + new_ent->seq = context->next_seq++; + new_ent->hash = hash; + + DEBUGF(fprintf(stderr, "deflatehd: indexed at %zu\n", + context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH)); + + if (map) { + hd_map_insert(map, new_ent); + } + context->hd_table_bufsize += room; } return new_ent; } -static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) { - return a->namelen == b->namelen && 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); -} - typedef struct { ssize_t index; /* Nonzero if both name and value are matched. */ @@ -1194,9 +1298,11 @@ static search_result search_static_table(const nghttp2_nv *nv, int token, static search_result search_hd_table(nghttp2_hd_context *context, const nghttp2_nv *nv, int token, - int indexing_mode) { + int indexing_mode, nghttp2_hd_map *map, + uint32_t hash) { search_result res = {-1, 0}; - size_t i; + nghttp2_hd_entry *ent; + int exact_match; if (token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) { res = search_static_table(nv, token, indexing_mode); @@ -1205,27 +1311,27 @@ static search_result search_hd_table(nghttp2_hd_context *context, } } - 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; - } + exact_match = 0; + ent = hd_map_find(map, &exact_match, nv, token, hash); + if (ent == NULL) { + return res; + } - if (res.index == -1) { - res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH); - } + if (res.index != -1 && !exact_match) { + 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; - } + res.index = context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH; + + if (exact_match) { + res.name_value_match = 1; } return res; } -static void hd_context_shrink_table_size(nghttp2_hd_context *context) { +static void hd_context_shrink_table_size(nghttp2_hd_context *context, + nghttp2_hd_map *map) { nghttp2_mem *mem; mem = context->mem; @@ -1236,6 +1342,9 @@ static void hd_context_shrink_table_size(nghttp2_hd_context *context) { nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); hd_ringbuf_pop_back(&context->hd_table); + if (map) { + hd_map_remove(map, ent); + } if (--ent->ref == 0) { nghttp2_hd_entry_free(ent, mem); nghttp2_mem_free(mem, ent); @@ -1255,7 +1364,7 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, deflater->notify_table_size_change = 1; - hd_context_shrink_table_size(&deflater->ctx); + hd_context_shrink_table_size(&deflater->ctx, &deflater->map); return 0; } @@ -1272,7 +1381,7 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE; inflater->settings_hd_table_bufsize_max = settings_hd_table_bufsize_max; inflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max; - hd_context_shrink_table_size(&inflater->ctx); + hd_context_shrink_table_size(&inflater->ctx, NULL); return 0; } @@ -1317,12 +1426,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, int indexing_mode; int token; nghttp2_mem *mem; + uint32_t hash; DEBUGF(fprintf(stderr, "deflatehd: deflating %s: %s\n", nv->name, nv->value)); mem = deflater->ctx.mem; token = lookup_token(nv->name, nv->namelen); + if (token == -1 || token > NGHTTP2_TOKEN_WWW_AUTHENTICATE) { + hash = name_hash(nv); + } else { + hash = static_table[token].hash; + } /* Don't index authorization header field since it may contain low entropy secret data (e.g., id/password). Also cookie header @@ -1335,7 +1450,8 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, ? NGHTTP2_HD_NEVER_INDEXING : hd_deflate_decide_indexing(deflater, nv, token); - res = search_hd_table(&deflater->ctx, nv, token, indexing_mode); + res = search_hd_table(&deflater->ctx, nv, token, indexing_mode, + &deflater->map, hash); idx = res.index; @@ -1343,7 +1459,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, DEBUGF(fprintf(stderr, "deflatehd: name/value match index=%zd\n", idx)); - rv = emit_indexed_block(bufs, idx); + rv = emit_indexed_block(bufs, (size_t)idx); if (rv != 0) { return rv; } @@ -1360,13 +1476,16 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, 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; + nv_indname.name = + nghttp2_hd_table_get(&deflater->ctx, (size_t)idx)->nv.name; new_ent = add_hd_table_incremental(&deflater->ctx, &nv_indname, token, - NGHTTP2_HD_FLAG_VALUE_ALLOC); + NGHTTP2_HD_FLAG_VALUE_ALLOC, + &deflater->map, hash); } else { new_ent = add_hd_table_incremental(&deflater->ctx, nv, token, NGHTTP2_HD_FLAG_NAME_ALLOC | - NGHTTP2_HD_FLAG_VALUE_ALLOC); + NGHTTP2_HD_FLAG_VALUE_ALLOC, + &deflater->map, hash); } if (!new_ent) { return NGHTTP2_ERR_HEADER_COMP; @@ -1379,7 +1498,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, if (idx == -1) { rv = emit_newname_block(bufs, nv, indexing_mode); } else { - rv = emit_indname_block(bufs, idx, nv, indexing_mode); + rv = emit_indname_block(bufs, (size_t)idx, nv, indexing_mode); } if (rv != 0) { return rv; @@ -1615,7 +1734,7 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, final = 1; } readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, bufs, in, - last - in, final); + (size_t)(last - in), final); if (readlen < 0) { DEBUGF(fprintf(stderr, "inflatehd: huffman decoding failed\n")); @@ -1689,7 +1808,7 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv, nghttp2_bufs_reset(&inflater->nvbufs); - buflen = rv; + buflen = (size_t)rv; if (value_only) { /* we don't use this value, so no need to NULL-terminate */ @@ -1816,8 +1935,9 @@ 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, lookup_token(nv.name, nv.namelen), ent_flags); + new_ent = add_hd_table_incremental(&inflater->ctx, &nv, + lookup_token(nv.name, nv.namelen), + ent_flags, NULL, 0); if (new_ent) { emit_indexed_header(nv_out, token_out, new_ent); @@ -1892,7 +2012,7 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, } new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token, - ent_flags); + ent_flags, NULL, 0); /* At this point, ent_name might be deleted. */ @@ -2021,7 +2141,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, } DEBUGF(fprintf(stderr, "inflatehd: table_size=%zu\n", inflater->left)); inflater->ctx.hd_table_bufsize_max = inflater->left; - hd_context_shrink_table_size(&inflater->ctx); + hd_context_shrink_table_size(&inflater->ctx, NULL); inflater->state = NGHTTP2_HD_STATE_INFLATE_START; break; case NGHTTP2_HD_STATE_READ_INDEX: { diff --git a/epan/nghttp2/nghttp2_hd.h b/epan/nghttp2/nghttp2_hd.h index e85a04b6e7..36adaf6ef4 100644 --- a/epan/nghttp2/nghttp2_hd.h +++ b/epan/nghttp2/nghttp2_hd.h @@ -126,15 +126,25 @@ typedef enum { NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 3 } nghttp2_hd_flags; -typedef struct { +struct nghttp2_hd_entry; +typedef struct nghttp2_hd_entry nghttp2_hd_entry; + +struct nghttp2_hd_entry { nghttp2_nv nv; + /* The next entry which shares same bucket in hash table. */ + nghttp2_hd_entry *next; + /* The sequence number. We will increment it by one whenever we + store nghttp2_hd_entry to dynamic header table. */ + uint32_t seq; + /* The hash value for header name (nv.name). */ + uint32_t hash; /* nghttp2_token value for nv.name. It could be -1 if we have no token for that header field name. */ int token; /* Reference count */ uint8_t ref; uint8_t flags; -} nghttp2_hd_entry; +}; typedef struct { nghttp2_hd_entry **buffer; @@ -183,14 +193,21 @@ typedef struct { size_t hd_table_bufsize; /* The effective header table size. */ size_t hd_table_bufsize_max; + /* Next sequence number for nghttp2_hd_entry */ + uint32_t next_seq; /* If inflate/deflate error occurred, this value is set to 1 and further invocation of inflate/deflate will fail with NGHTTP2_ERR_HEADER_COMP. */ uint8_t bad; } nghttp2_hd_context; +#define HD_MAP_SIZE 128 + +typedef struct { nghttp2_hd_entry *table[HD_MAP_SIZE]; } nghttp2_hd_map; + struct nghttp2_hd_deflater { nghttp2_hd_context ctx; + nghttp2_hd_map map; /* The upper limit of the header table size the deflater accepts. */ size_t deflate_hd_table_bufsize_max; /* Minimum header table size notified in the next context update */ diff --git a/epan/nghttp2/nghttp2_hd_huffman.c b/epan/nghttp2/nghttp2_hd_huffman.c index 4df1cd0425..fb2d167b03 100644 --- a/epan/nghttp2/nghttp2_hd_huffman.c +++ b/epan/nghttp2/nghttp2_hd_huffman.c @@ -48,17 +48,17 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr, /* We assume that sym->nbits <= 32 */ if (rembits > nbits) { - nghttp2_bufs_fast_orb_hold(bufs, code << (rembits - nbits)); + nghttp2_bufs_fast_orb_hold(bufs, (uint8_t)(code << (rembits - nbits))); return (ssize_t)(rembits - nbits); } if (rembits == nbits) { - nghttp2_bufs_fast_orb(bufs, code); + nghttp2_bufs_fast_orb(bufs, (uint8_t)code); --*avail_ptr; return 8; } - nghttp2_bufs_fast_orb(bufs, code >> (nbits - rembits)); + nghttp2_bufs_fast_orb(bufs, (uint8_t)(code >> (nbits - rembits))); --*avail_ptr; nbits -= rembits; @@ -80,34 +80,34 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr, /* fast path, since most code is less than 8 */ if (nbits < 8) { - nghttp2_bufs_fast_addb_hold(bufs, code); + nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); *avail_ptr = nghttp2_bufs_cur_avail(bufs); return (ssize_t)(8 - nbits); } /* handle longer code path */ if (nbits > 24) { - nghttp2_bufs_fast_addb(bufs, code >> 24); + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 24)); nbits -= 8; } if (nbits > 16) { - nghttp2_bufs_fast_addb(bufs, code >> 16); + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 16)); nbits -= 8; } if (nbits > 8) { - nghttp2_bufs_fast_addb(bufs, code >> 8); + nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 8)); nbits -= 8; } if (nbits == 8) { - nghttp2_bufs_fast_addb(bufs, code); + nghttp2_bufs_fast_addb(bufs, (uint8_t)code); *avail_ptr = nghttp2_bufs_cur_avail(bufs); return 8; } - nghttp2_bufs_fast_addb_hold(bufs, code); + nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); *avail_ptr = nghttp2_bufs_cur_avail(bufs); return (ssize_t)(8 - nbits); } @@ -145,7 +145,7 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, avail = nghttp2_bufs_cur_avail(bufs); } } - rembits = huff_encode_sym(bufs, &avail, rembits, sym); + rembits = huff_encode_sym(bufs, &avail, (size_t)rembits, sym); if (rembits < 0) { return (int)rembits; } @@ -157,7 +157,7 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, const nghttp2_huff_sym *sym = &huff_sym_table[256]; assert(avail); /* Caution we no longer adjust avail here */ - nghttp2_bufs_fast_orb(bufs, sym->code >> (sym->nbits - rembits)); + nghttp2_bufs_fast_orb(bufs, (uint8_t)(sym->code >> (sym->nbits - rembits))); } return 0; diff --git a/epan/nghttp2/nghttp2_hd_huffman.h b/epan/nghttp2/nghttp2_hd_huffman.h index a364e4bfe6..e51ee48bb2 100644 --- a/epan/nghttp2/nghttp2_hd_huffman.h +++ b/epan/nghttp2/nghttp2_hd_huffman.h @@ -71,4 +71,7 @@ typedef struct { uint32_t code; } nghttp2_huff_sym; +extern const nghttp2_huff_sym huff_sym_table[]; +extern const nghttp2_huff_decode huff_decode_table[][16]; + #endif /* NGHTTP2_HD_HUFFMAN_H */ diff --git a/epan/nghttp2/nghttp2_helper.c b/epan/nghttp2/nghttp2_helper.c index aeb2c962ff..c75e082424 100644 --- a/epan/nghttp2/nghttp2_helper.c +++ b/epan/nghttp2/nghttp2_helper.c @@ -67,7 +67,7 @@ void *nghttp2_memdup(const void *src, size_t n, nghttp2_mem *mem) { } /* Generated by gendowncasetbl.py */ -static const int DOWNCASE_TBL[] = { +static const uint8_t DOWNCASE_TBL[] = { 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, 4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */, 8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */, diff --git a/epan/nghttp2/nghttp2_helper.h b/epan/nghttp2/nghttp2_helper.h index aa460cc7c8..48008cf4f6 100644 --- a/epan/nghttp2/nghttp2_helper.h +++ b/epan/nghttp2/nghttp2_helper.h @@ -40,11 +40,8 @@ #define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0) -#define nghttp2_struct_of(ptr, type, member) \ - ({ \ - const typeof(((type *)0)->member) *nghttp2__mptr = (nghttp2_pq_entry *)(ptr); \ - (type *)(void *)((char *)nghttp2__mptr - __builtin_offsetof(type, member)); \ - }) +#define nghttp2_struct_of(ptr, type, member) \ + ((type *)(void *)((char *)(ptr) - offsetof(type, member))) /* * Copies 2 byte unsigned integer |n| in host byte order to |buf| in diff --git a/epan/nghttp2/nghttp2ver.h b/epan/nghttp2/nghttp2ver.h index fc5dbd193d..173f4648cd 100644 --- a/epan/nghttp2/nghttp2ver.h +++ b/epan/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.3.0" +#define NGHTTP2_VERSION "1.3.3" /** * @macro @@ -37,6 +37,6 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define NGHTTP2_VERSION_NUM 0x010300 +#define NGHTTP2_VERSION_NUM 0x010303 #endif /* NGHTTP2VER_H */ |