diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 45e53589..0aab61d8 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -766,10 +766,17 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater, /* Check name exists in hd_table */ ent = find_name_in_hd_table(deflater, &nv[i]); if(ent) { - /* As long as no eviction kicked in, perform substitution */ - if(require_eviction_on_subst(deflater, &nv[i], ent)) { + /* As long as no eviction kicked in and the same header + field name is not indexed and added, perform + substitution. Since we never evict anything, searching + ent->index in working set is safe. */ + if(require_eviction_on_subst(deflater, &nv[i], ent) || + find_in_workingset_by_index(deflater, ent->index)) { rv = emit_indname_block(buf_ptr, buflen_ptr, &offset, ent, nv[i].value, nv[i].valuelen, 0); + if(rv < 0) { + return rv; + } } else { nghttp2_hd_entry *new_ent; /* No need to increment ent->ref here */ diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index d66867db..cc5eb6b6 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -51,6 +51,12 @@ void test_nghttp2_hd_deflate(void) MAKE_NV("hello", "world")}; nghttp2_nv nva2[] = {MAKE_NV(":path", "/script.js"), MAKE_NV(":scheme", "https")}; + nghttp2_nv nva3[] = {MAKE_NV(":path", "/style.css"), + MAKE_NV("cookie", "k1=v1"), + MAKE_NV("cookie", "k2=v2")}; + nghttp2_nv nva4[] = {MAKE_NV(":path", "/style.css"), + MAKE_NV("cookie", "k1=v1"), + MAKE_NV("cookie", "k1=v1")}; size_t nv_offset = 12; uint8_t *buf = NULL; size_t buflen = 0; @@ -89,6 +95,36 @@ void test_nghttp2_hd_deflate(void) nghttp2_nv_array_del(resnva); nghttp2_hd_end_headers(&inflater); + /* Third headers, including same header field name, but value is not + the same. */ + blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva3, + sizeof(nva3)/sizeof(nghttp2_nv)); + CU_ASSERT(blocklen > 0); + nghttp2_hd_end_headers(&deflater); + + CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset, + blocklen)); + + assert_nv_equal(nva3, resnva, 3); + + nghttp2_nv_array_del(resnva); + nghttp2_hd_end_headers(&inflater); + + /* Fourth headers, including duplicate header fields. We don't + encode duplicates. Only first one is encoded. */ + blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva4, + sizeof(nva4)/sizeof(nghttp2_nv)); + CU_ASSERT(blocklen == 0); + nghttp2_hd_end_headers(&deflater); + + CU_ASSERT(2 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset, + blocklen)); + + assert_nv_equal(nva4, resnva, 2); + + nghttp2_nv_array_del(resnva); + nghttp2_hd_end_headers(&inflater); + free(buf); nghttp2_hd_inflate_free(&inflater); nghttp2_hd_deflate_free(&deflater);