nghttp2_hd: Add static table entry to dynamic table on emission

This commit is contained in:
Tatsuhiro Tsujikawa 2013-10-24 21:52:02 +09:00
parent b193069110
commit 5a81e03497
2 changed files with 67 additions and 31 deletions

View File

@ -796,7 +796,28 @@ static int deflate_nv(nghttp2_hd_context *deflater,
if(rv != -1) { if(rv != -1) {
size_t index = rv; size_t index = rv;
ent = nghttp2_hd_table_get(deflater, index); ent = nghttp2_hd_table_get(deflater, index);
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) { if(index >= deflater->hd_table.len) {
nghttp2_hd_entry *new_ent;
/* It is important to first add entry to the header table and
let eviction go. If NGHTTP2_HD_FLAG_IMPLICIT_EMIT entry is
evicted, it must be emitted before the |nv|. */
new_ent = add_hd_table_incremental(deflater, buf_ptr, buflen_ptr,
offset_ptr, &ent->nv,
NGHTTP2_HD_FLAG_NONE);
if(!new_ent) {
return NGHTTP2_ERR_HEADER_COMP;
}
if(new_ent->ref == 0) {
nghttp2_hd_entry_free(new_ent);
free(new_ent);
} else {
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
}
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) {
return rv;
}
} else if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) {
ent->flags |= NGHTTP2_HD_FLAG_REFSET | NGHTTP2_HD_FLAG_EMIT; ent->flags |= NGHTTP2_HD_FLAG_REFSET | NGHTTP2_HD_FLAG_EMIT;
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) { if(rv != 0) {
@ -859,7 +880,12 @@ static int deflate_nv(nghttp2_hd_context *deflater,
if(!new_ent) { if(!new_ent) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; if(new_ent->ref == 0) {
nghttp2_hd_entry_free(new_ent);
free(new_ent);
} else {
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
}
incidx = 1; incidx = 1;
} }
if(index == -1) { if(index == -1) {
@ -923,14 +949,6 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
goto fail; goto fail;
} }
} }
for(i = 0; deflater->static_hd_table[i]; ++i) {
nghttp2_hd_entry *ent = deflater->static_hd_table[i];
rv = deflate_post_process_hd_entry(ent, i + deflater->hd_table.len,
buf_ptr, buflen_ptr, &offset);
if(rv != 0) {
goto fail;
}
}
return offset - nv_offset; return offset - nv_offset;
fail: fail:
deflater->bad = 1; deflater->bad = 1;
@ -1003,12 +1021,25 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
ent = nghttp2_hd_table_get(inflater, index); ent = nghttp2_hd_table_get(inflater, index);
ent->flags ^= NGHTTP2_HD_FLAG_REFSET; if(index >= (ssize_t)inflater->hd_table.len) {
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) { nghttp2_hd_entry *new_ent;
rv = emit_indexed_header(inflater, &nva_out, ent); new_ent = add_hd_table_incremental(inflater, NULL, NULL, NULL,
if(rv != 0) { &ent->nv, NGHTTP2_HD_FLAG_NONE);
if(!new_ent) {
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
} }
/* new_ent->ref == 0 may be hold but emit_indexed_header
tracks new_ent, so there is no leak. */
rv = emit_indexed_header(inflater, &nva_out, new_ent);
} else {
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
rv = emit_indexed_header(inflater, &nva_out, ent);
}
}
if(rv != 0) {
goto fail;
} }
} else if(c == 0x40u || c == 0) { } else if(c == 0x40u || c == 0) {
/* Literal Header Repr - New Name */ /* Literal Header Repr - New Name */
@ -1191,13 +1222,6 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
} }
for(i = 0; inflater->static_hd_table[i]; ++i) {
nghttp2_hd_entry *ent = inflater->static_hd_table[i];
rv = inflater_post_process_hd_entry(inflater, ent, &nva_out);
if(rv != 0) {
goto fail;
}
}
nghttp2_nv_array_sort(nva_out.nva, nva_out.nvlen); nghttp2_nv_array_sort(nva_out.nva, nva_out.nvlen);
*nva_ptr = nva_out.nva; *nva_ptr = nva_out.nva;
return nva_out.nvlen; return nva_out.nvlen;

View File

@ -198,13 +198,13 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
size_t buflen = 0; size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
nghttp2_nv *resnva; nghttp2_nv *resnva;
/* Default header table capacity is 1262. Adding 2835 bytes, /* Default header table capacity is 4096. Adding 2 byte header name
including overhead, to the table evicts first entry. and 4060 byte value, which is 4094 bytes including overhead, to
use name ":host" which index 2 and value length 2798. */ the table evicts first entry. */
uint8_t value[2798]; uint8_t value[4060];
memset(value, '0', sizeof(value)); memset(value, '0', sizeof(value));
nva[1].name = (uint8_t*)":host"; nva[1].name = (uint8_t*)"hd";
nva[1].namelen = strlen((const char*)nva[1].name); nva[1].namelen = strlen((const char*)nva[1].name);
nva[1].value = value; nva[1].value = value;
nva[1].valuelen = sizeof(value); nva[1].valuelen = sizeof(value);
@ -212,11 +212,20 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
/* Put :scheme: http (index = 0) in reference set */ /* First emit ":scheme: http" to put it in the reference set (index
GET_TABLE_ENT(&deflater, 0)->flags |= NGHTTP2_HD_FLAG_REFSET; = 0). */
GET_TABLE_ENT(&inflater, 0)->flags |= NGHTTP2_HD_FLAG_REFSET; blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 1);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, CU_ASSERT(blocklen > 0);
sizeof(nva)/sizeof(nghttp2_nv)); nghttp2_hd_end_headers(&deflater);
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, blocklen));
nghttp2_nv_array_sort(nva, 1);
assert_nv_equal(nva, resnva, 1);
nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater);
/* Encode with large header */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
nghttp2_hd_end_headers(&deflater); nghttp2_hd_end_headers(&deflater);
@ -230,6 +239,9 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater); nghttp2_hd_end_headers(&inflater);
CU_ASSERT(1 == deflater.hd_table.len);
CU_ASSERT(1 == inflater.hd_table.len);
free(buf); free(buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);