HPACK post -05 updates

* Use 1 Huffman code table for both request and response
* Remove complicated deflater side table size management
* Add encoding context update
* Fix memory leak in inflater
This commit is contained in:
Tatsuhiro Tsujikawa 2014-02-13 23:22:52 +09:00
parent 082876d92d
commit fd88c6160d
19 changed files with 471 additions and 5771 deletions

View File

@ -286,13 +286,10 @@ static void nghttp2_hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf)
} }
static int nghttp2_hd_context_init(nghttp2_hd_context *context, static int nghttp2_hd_context_init(nghttp2_hd_context *context,
nghttp2_hd_role role, nghttp2_hd_role role)
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max)
{ {
int rv; int rv;
context->role = role; context->role = role;
context->side = side;
context->bad = 0; context->bad = 0;
context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
rv = nghttp2_hd_ringbuf_init rv = nghttp2_hd_ringbuf_init
@ -302,41 +299,41 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context,
return rv; return rv;
} }
context->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max;
context->deflate_hd_table_bufsize = 0;
context->deflate_hd_tablelen = 0;
context->hd_table_bufsize = 0; context->hd_table_bufsize = 0;
return 0; return 0;
} }
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_hd_side side) int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater)
{ {
return nghttp2_hd_deflate_init2(deflater, side, return nghttp2_hd_deflate_init2(deflater,
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE); NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
} }
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max) size_t deflate_hd_table_bufsize_max)
{ {
int rv; int rv;
rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE, side, rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE);
deflate_hd_table_bufsize_max);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
deflater->no_refset = 0; deflater->no_refset = 0;
deflater->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max;
return 0; return 0;
} }
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_hd_side side) int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater)
{ {
int rv; int rv;
rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE, side,
NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE); rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
inflater->settings_hd_table_bufsize_max =
NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
inflater->ent_keep = NULL; inflater->ent_keep = NULL;
inflater->name_keep = NULL; inflater->name_keep = NULL;
inflater->value_keep = NULL; inflater->value_keep = NULL;
@ -559,16 +556,38 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
return in + 1; return in + 1;
} }
static int emit_indexed0(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_clear_refset(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr) size_t *offset_ptr)
{ {
int rv; int rv;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 1); uint8_t *bufp;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 2);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
*(*buf_ptr + *offset_ptr) = 0x80u; bufp = *buf_ptr + *offset_ptr;
++*offset_ptr; *bufp++ = 0x80u;
*bufp = 0x80u;
*offset_ptr += 2;
return 0;
}
static int emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size)
{
int rv;
uint8_t *bufp;
size_t blocklen = 1 + count_encoded_length(table_size, 7);
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
if(rv != 0) {
return rv;
}
DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size));
bufp = *buf_ptr + *offset_ptr;
*bufp++ = 0x80u;
*bufp = 0;
encode_length(bufp, table_size, 7);
*offset_ptr += blocklen;
return 0; return 0;
} }
@ -591,15 +610,14 @@ static int emit_indexed_block(uint8_t **buf_ptr, size_t *buflen_ptr,
static size_t emit_string(uint8_t *buf, size_t buflen, static size_t emit_string(uint8_t *buf, size_t buflen,
size_t enclen, int huffman, size_t enclen, int huffman,
const uint8_t *str, size_t len, const uint8_t *str, size_t len)
nghttp2_hd_side side)
{ {
size_t rv; size_t rv;
*buf = huffman ? 1 << 7 : 0; *buf = huffman ? 1 << 7 : 0;
rv = encode_length(buf, enclen, 7); rv = encode_length(buf, enclen, 7);
buf += rv; buf += rv;
if(huffman) { if(huffman) {
nghttp2_hd_huff_encode(buf, buflen - rv, str, len, side); nghttp2_hd_huff_encode(buf, buflen - rv, str, len);
} else { } else {
assert(enclen == len); assert(enclen == len);
memcpy(buf, str, len); memcpy(buf, str, len);
@ -610,12 +628,11 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index, size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing, int inc_indexing)
nghttp2_hd_side side)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen, side); size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
size_t blocklen = count_encoded_length(index + 1, 6); size_t blocklen = count_encoded_length(index + 1, 6);
int huffman = encvallen < valuelen; int huffman = encvallen < valuelen;
if(!huffman) { if(!huffman) {
@ -630,7 +647,7 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
*bufp = inc_indexing ? 0 : 0x40u; *bufp = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, index + 1, 6); bufp += encode_length(bufp, index + 1, 6);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
encvallen, huffman, value, valuelen, side); encvallen, huffman, value, valuelen);
assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen); assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen);
*offset_ptr += blocklen; *offset_ptr += blocklen;
return 0; return 0;
@ -638,15 +655,14 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv, size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing, int inc_indexing)
nghttp2_hd_side side)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t encnamelen = size_t encnamelen =
nghttp2_hd_huff_encode_count(nv->name, nv->namelen, side); nghttp2_hd_huff_encode_count(nv->name, nv->namelen);
size_t encvallen = size_t encvallen =
nghttp2_hd_huff_encode_count(nv->value, nv->valuelen, side); nghttp2_hd_huff_encode_count(nv->value, nv->valuelen);
size_t blocklen = 1; size_t blocklen = 1;
int name_huffman = encnamelen < nv->namelen; int name_huffman = encnamelen < nv->namelen;
int value_huffman = encvallen < nv->valuelen; int value_huffman = encvallen < nv->valuelen;
@ -665,9 +681,9 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
bufp = *buf_ptr + *offset_ptr; bufp = *buf_ptr + *offset_ptr;
*bufp++ = inc_indexing ? 0 : 0x40u; *bufp++ = inc_indexing ? 0 : 0x40u;
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
encnamelen, name_huffman, nv->name, nv->namelen, side); encnamelen, name_huffman, nv->name, nv->namelen);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
encvallen, value_huffman, nv->value, nv->valuelen, side); encvallen, value_huffman, nv->value, nv->valuelen);
*offset_ptr += blocklen; *offset_ptr += blocklen;
return 0; return 0;
} }
@ -707,11 +723,6 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
size_t index = context->hd_table.len - 1; size_t index = context->hd_table.len - 1;
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index); nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) {
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
ent->nv.valuelen);
--context->deflate_hd_tablelen;
}
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) { if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
/* Emit common header just before it slips away from the /* Emit common header just before it slips away from the
@ -734,82 +745,19 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
free(ent); free(ent);
} }
} }
while(context->deflate_hd_table_bufsize + room >
context->deflate_hd_table_bufsize_max
&& context->deflate_hd_tablelen > 0) {
size_t index = context->deflate_hd_tablelen - 1;
nghttp2_hd_entry *ent =
nghttp2_hd_ringbuf_get(&context->hd_table, index);
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
ent->nv.valuelen);
--context->deflate_hd_tablelen;
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
/* Just like a normal eviction, implicit header must be
emitted twice. */
rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) {
return NULL;
}
ent->flags ^= NGHTTP2_HD_FLAG_IMPLICIT_EMIT;
}
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
/* We need to drop entry from reference set. */
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) {
return NULL;
}
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
}
/* Release memory. We don't remove entry from the header table
at this moment. */
if(ent->flags & NGHTTP2_HD_FLAG_NAME_ALLOC) {
free(ent->nv.name);
ent->nv.name = NULL;
ent->flags ^= NGHTTP2_HD_FLAG_NAME_ALLOC;
}
if(ent->flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) {
free(ent->nv.value);
ent->nv.value = NULL;
ent->flags ^= NGHTTP2_HD_FLAG_VALUE_ALLOC;
}
}
new_ent = malloc(sizeof(nghttp2_hd_entry)); new_ent = malloc(sizeof(nghttp2_hd_entry));
if(new_ent == NULL) { if(new_ent == NULL) {
return NULL; return NULL;
} }
if(context->role == NGHTTP2_HD_ROLE_DEFLATE && rv = nghttp2_hd_entry_init(new_ent, entry_flags,
room > context->deflate_hd_table_bufsize_max) {
uint8_t flags = entry_flags &
~(NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC |
NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT);
rv = nghttp2_hd_entry_init(new_ent, flags,
NULL, nv->namelen, NULL, nv->valuelen);
if(rv != 0) {
free(new_ent);
return NULL;
}
if(flags & NGHTTP2_HD_FLAG_NAME_GIFT) {
free(nv->name);
nv->name = NULL;
}
if(flags & NGHTTP2_HD_FLAG_VALUE_GIFT) {
free(nv->value);
nv->value = NULL;
}
/* caller must emit indexed repr to toggle off new_ent from
reference set. We cannot do it here because it may break the
indexing. */
} else {
rv = nghttp2_hd_entry_init(new_ent,
entry_flags,
nv->name, nv->namelen, nv->value, nv->valuelen); nv->name, nv->namelen, nv->value, nv->valuelen);
if(rv != 0) { if(rv != 0) {
free(new_ent); free(new_ent);
return NULL; return NULL;
} }
}
if(room > context->hd_table_bufsize_max) { if(room > context->hd_table_bufsize_max) {
/* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is
immediately evicted. */ immediately evicted. */
@ -817,11 +765,8 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
} else { } else {
context->hd_table_bufsize += room; context->hd_table_bufsize += room;
nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent); nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent);
if(room <= context->deflate_hd_table_bufsize_max) {
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET; new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
context->deflate_hd_table_bufsize += room;
++context->deflate_hd_tablelen;
}
} }
return new_ent; return new_ent;
} }
@ -851,7 +796,7 @@ static search_result search_hd_table(nghttp2_hd_context *context,
uint32_t value_hash = hash(nv->value, nv->valuelen); uint32_t value_hash = hash(nv->value, nv->valuelen);
ssize_t left = -1, right = STATIC_TABLE_LENGTH; ssize_t left = -1, right = STATIC_TABLE_LENGTH;
for(i = 0; i < context->deflate_hd_tablelen; ++i) { for(i = 0; i < context->hd_table.len; ++i) {
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i); nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i);
if(ent->name_hash == name_hash && name_eq(&ent->nv, nv)) { if(ent->name_hash == name_hash && name_eq(&ent->nv, nv)) {
if(res.index == -1) { if(res.index == -1) {
@ -893,35 +838,59 @@ static search_result search_hd_table(nghttp2_hd_context *context,
return res; return res;
} }
int nghttp2_hd_change_table_size(nghttp2_hd_context *context, static void hd_context_shrink_table_size(nghttp2_hd_context *context)
size_t hd_table_bufsize_max)
{ {
int rv;
rv = nghttp2_hd_ringbuf_reserve
(&context->hd_table, hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD);
if(rv != 0) {
return rv;
}
context->hd_table_bufsize_max = hd_table_bufsize_max;
if(context->role == NGHTTP2_HD_ROLE_INFLATE) {
context->deflate_hd_table_bufsize_max = hd_table_bufsize_max;
}
while(context->hd_table_bufsize > context->hd_table_bufsize_max && while(context->hd_table_bufsize > context->hd_table_bufsize_max &&
context->hd_table.len > 0) { context->hd_table.len > 0) {
size_t index = context->hd_table.len - 1; size_t index = context->hd_table.len - 1;
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index); nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) {
context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen,
ent->nv.valuelen);
--context->deflate_hd_tablelen;
}
nghttp2_hd_ringbuf_pop_back(&context->hd_table); nghttp2_hd_ringbuf_pop_back(&context->hd_table);
if(--ent->ref == 0) { if(--ent->ref == 0) {
nghttp2_hd_entry_free(ent); nghttp2_hd_entry_free(ent);
free(ent); free(ent);
} }
} }
}
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t settings_hd_table_bufsize_max)
{
int rv;
size_t next_bufsize = nghttp2_min(settings_hd_table_bufsize_max,
deflater->deflate_hd_table_bufsize_max);
rv = nghttp2_hd_ringbuf_reserve
(&deflater->ctx.hd_table, next_bufsize / NGHTTP2_HD_ENTRY_OVERHEAD);
if(rv != 0) {
return rv;
}
deflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max;
if(settings_hd_table_bufsize_max >= deflater->deflate_hd_table_bufsize_max) {
/* On the next encoding, we sends encoding context update with
deflater->deflate_hd_table_bufsize_max if it is strictly
smaller than settings_hd_table_bufsize_max. */
return 0;
}
hd_context_shrink_table_size(&deflater->ctx);
return 0;
}
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t settings_hd_table_bufsize_max)
{
int rv;
rv = nghttp2_hd_ringbuf_reserve
(&inflater->ctx.hd_table,
settings_hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD);
if(rv != 0) {
return rv;
}
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);
return 0; return 0;
} }
@ -962,9 +931,8 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater, static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
const nghttp2_nv *nv) const nghttp2_nv *nv)
{ {
size_t table_size = nghttp2_min(deflater->ctx.deflate_hd_table_bufsize_max, if(entry_room(nv->namelen, nv->valuelen) >
deflater->ctx.hd_table_bufsize_max); deflater->ctx.hd_table_bufsize_max * 3 / 4) {
if(entry_room(nv->namelen, nv->valuelen) > table_size * 3 / 4) {
return 0; return 0;
} }
#ifdef NGHTTP2_XHD #ifdef NGHTTP2_XHD
@ -1006,9 +974,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
nghttp2_hd_entry_free(new_ent); nghttp2_hd_entry_free(new_ent);
free(new_ent); free(new_ent);
new_ent = NULL; new_ent = NULL;
} else if(new_ent->nv.name != NULL) { } else {
/* new_ent->ref > 0 and nv.name is not NULL means that new_ent is /* new_ent->ref > 0 means that new_ent is in the reference
in the reference set and in deflate_hd_table_bufsize */ set */
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; new_ent->flags |= 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);
@ -1080,20 +1048,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
if(new_ent->ref == 0) { if(new_ent->ref == 0) {
nghttp2_hd_entry_free(new_ent); nghttp2_hd_entry_free(new_ent);
free(new_ent); free(new_ent);
} else if(new_ent->nv.name != NULL) { } else {
/* new_ent->ref > 0 and nv.name is not NULL means that new_ent is /* new_ent->ref > 0 means that new_ent is in the reference
in the reference set and in deflate_hd_table_bufsize */ set. */
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
} }
incidx = 1; incidx = 1;
} }
if(index == -1) { if(index == -1) {
rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx, rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx);
deflater->ctx.side);
} else { } else {
rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index, rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index,
nv->value, nv->valuelen, incidx, nv->value, nv->valuelen, incidx);
deflater->ctx.side);
} }
if(rv != 0) { if(rv != 0) {
return rv; return rv;
@ -1135,8 +1101,20 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
offset = nv_offset; offset = nv_offset;
if(deflater->ctx.hd_table_bufsize_max >
deflater->deflate_hd_table_bufsize_max) {
rv = emit_table_size(buf_ptr, buflen_ptr, &offset,
deflater->deflate_hd_table_bufsize_max);
if(rv != 0) {
goto fail;
}
deflater->ctx.hd_table_bufsize_max =
deflater->deflate_hd_table_bufsize_max;
}
if(deflater->no_refset) { if(deflater->no_refset) {
rv = emit_indexed0(buf_ptr, buflen_ptr, &offset); rv = emit_clear_refset(buf_ptr, buflen_ptr, &offset);
if(rv != 0) { if(rv != 0) {
goto fail; goto fail;
} }
@ -1148,7 +1126,7 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
goto fail; goto fail;
} }
} }
for(i = 0; i < deflater->ctx.deflate_hd_tablelen; ++i) { for(i = 0; i < deflater->ctx.hd_table.len; ++i) {
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i); nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i);
rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset); rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset);
if(rv != 0) { if(rv != 0) {
@ -1414,11 +1392,17 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
DEBUGF(fprintf(stderr, "nghtp2_hd_infalte_hd start state=%d\n", DEBUGF(fprintf(stderr, "nghtp2_hd_infalte_hd start state=%d\n",
inflater->state)); inflater->state));
hd_inflate_keep_free(inflater);
*inflate_flags = NGHTTP2_HD_INFLATE_NONE; *inflate_flags = NGHTTP2_HD_INFLATE_NONE;
for(; in != last;) { for(; in != last;) {
switch(inflater->state) { switch(inflater->state) {
case NGHTTP2_HD_STATE_OPCODE: case NGHTTP2_HD_STATE_OPCODE:
if(*in & 0x80u) { if(*in == 0x80u) {
DEBUGF(fprintf(stderr, "Encoding context update\n"));
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
inflater->state = NGHTTP2_HD_STATE_CONTEXT_UPDATE;
++in;
} else if(*in & 0x80u) {
DEBUGF(fprintf(stderr, "Indexed repr\n")); DEBUGF(fprintf(stderr, "Indexed repr\n"));
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
inflater->state = NGHTTP2_HD_STATE_READ_INDEX; inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
@ -1441,6 +1425,38 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
} }
inflater->left = 0; inflater->left = 0;
break; break;
case NGHTTP2_HD_STATE_CONTEXT_UPDATE:
if(*in & 0x80u) {
if(*in != 0x80u) {
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
++in;
DEBUGF(fprintf(stderr, "Clearing reference set\n"));
clear_refset(&inflater->ctx);
inflater->state = NGHTTP2_HD_STATE_OPCODE;
break;
}
/* Header table size change */
DEBUGF(fprintf(stderr, "Header table size change\n"));
inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
break;
case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
rfin = 0;
rv = hd_inflate_read_len(inflater, &rfin, in, last, 7,
inflater->settings_hd_table_bufsize_max);
if(rv < 0) {
goto fail;
}
in += rv;
if(!rfin) {
return in - first;
}
DEBUGF(fprintf(stderr, "table_size=%zd\n", inflater->left));
inflater->ctx.hd_table_bufsize_max = inflater->left;
hd_context_shrink_table_size(&inflater->ctx);
inflater->state = NGHTTP2_HD_STATE_OPCODE;
break;
case NGHTTP2_HD_STATE_READ_INDEX: case NGHTTP2_HD_STATE_READ_INDEX:
rfin = 0; rfin = 0;
rv = hd_inflate_read_len(inflater, &rfin, in, last, rv = hd_inflate_read_len(inflater, &rfin, in, last,
@ -1457,12 +1473,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
DEBUGF(fprintf(stderr, "index=%zd\n", inflater->left)); DEBUGF(fprintf(stderr, "index=%zd\n", inflater->left));
if(inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { if(inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
inflater->index = inflater->left; inflater->index = inflater->left;
if(inflater->index == 0) { assert(inflater->index > 0);
DEBUGF(fprintf(stderr, "Clearing reference set\n"));
clear_refset(&inflater->ctx);
inflater->state = NGHTTP2_HD_STATE_OPCODE;
break;
}
--inflater->index; --inflater->index;
rv = hd_inflate_commit_indexed(inflater, nv_out); rv = hd_inflate_commit_indexed(inflater, nv_out);
if(rv < 0) { if(rv < 0) {
@ -1504,8 +1515,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
} }
rv = 0; rv = 0;
if(inflater->huffman_encoded) { if(inflater->huffman_encoded) {
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx, nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
inflater->ctx.side);
rv = nghttp2_buffer_reserve(&inflater->namebuf, rv = nghttp2_buffer_reserve(&inflater->namebuf,
guess_huff_decode_len(inflater->left)); guess_huff_decode_len(inflater->left));
if(rv != 0) { if(rv != 0) {
@ -1579,8 +1589,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
return in - first; return in - first;
} }
if(inflater->huffman_encoded) { if(inflater->huffman_encoded) {
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx, nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
inflater->ctx.side);
rv = nghttp2_buffer_reserve(&inflater->valuebuf, rv = nghttp2_buffer_reserve(&inflater->valuebuf,
guess_huff_decode_len(inflater->left)); guess_huff_decode_len(inflater->left));
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
@ -1678,19 +1687,21 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater)
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index, size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing, int inc_indexing)
nghttp2_hd_side side)
{ {
return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr,
index, value, valuelen, inc_indexing, index, value, valuelen, inc_indexing);
side);
} }
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv, size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing, int inc_indexing)
nghttp2_hd_side side)
{ {
return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing, return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing);
side); }
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size)
{
return emit_table_size(buf_ptr, buflen_ptr, offset_ptr, table_size);
} }

View File

@ -22,8 +22,8 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef NGHTTP2_HD_COMP_H #ifndef NGHTTP2_HD_H
#define NGHTTP2_HD_COMP_H #define NGHTTP2_HD_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
@ -48,11 +48,6 @@
encoder only uses the memory up to this value. */ encoder only uses the memory up to this value. */
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12) #define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
typedef enum {
NGHTTP2_HD_SIDE_REQUEST = 0,
NGHTTP2_HD_SIDE_RESPONSE = 1
} nghttp2_hd_side;
typedef enum { typedef enum {
NGHTTP2_HD_ROLE_DEFLATE, NGHTTP2_HD_ROLE_DEFLATE,
NGHTTP2_HD_ROLE_INFLATE NGHTTP2_HD_ROLE_INFLATE
@ -108,6 +103,8 @@ typedef enum {
typedef enum { typedef enum {
NGHTTP2_HD_STATE_OPCODE, NGHTTP2_HD_STATE_OPCODE,
NGHTTP2_HD_STATE_CONTEXT_UPDATE,
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
NGHTTP2_HD_STATE_READ_INDEX, NGHTTP2_HD_STATE_READ_INDEX,
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN, NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN, NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
@ -126,30 +123,10 @@ typedef struct {
is the sum of length of name/value in hd_table + is the sum of length of name/value in hd_table +
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */ NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
size_t hd_table_bufsize; size_t hd_table_bufsize;
/* The header table size for decoding. If the context is initialized /* The effective header table size. */
as encoder, this value is advertised by remote endpoint
decoder. */
size_t hd_table_bufsize_max; size_t hd_table_bufsize_max;
/* The current effective header table size for encoding. This value
is always equal to |hd_table_bufsize| on decoder
context. |deflate_hd_table_bufsize| <= |hd_table_bufsize| must be
hold. */
size_t deflate_hd_table_bufsize;
/* The maximum effective header table for encoding. Although header
table size is bounded by |hd_table_bufsize_max|, the encoder can
use smaller buffer by not retaining the header name/values beyond
the |deflate_hd_table_bufsize_max| and not referencing those
entries. This value is always equal to |hd_table_bufsize_max| on
decoder context. */
size_t deflate_hd_table_bufsize_max;
/* The number of effective entry in |hd_table|. This value is always
equal to hd_table.len on decoder side. */
size_t deflate_hd_tablelen;
/* Role of this context; deflate or infalte */ /* Role of this context; deflate or infalte */
nghttp2_hd_role role; nghttp2_hd_role role;
/* NGHTTP2_HD_SIDE_REQUEST for processing request, otherwise
response. */
nghttp2_hd_side side;
/* If inflate/deflate error occurred, this value is set to 1 and /* If inflate/deflate error occurred, this value is set to 1 and
further invocation of inflate/deflate will fail with further invocation of inflate/deflate will fail with
NGHTTP2_ERR_HEADER_COMP. */ NGHTTP2_ERR_HEADER_COMP. */
@ -158,6 +135,8 @@ typedef struct {
typedef struct { typedef struct {
nghttp2_hd_context ctx; nghttp2_hd_context ctx;
/* The upper limit of the header table size the deflater accepts. */
size_t deflate_hd_table_bufsize_max;
/* Set to this nonzero to clear reference set on each deflation each /* Set to this nonzero to clear reference set on each deflation each
time. */ time. */
uint8_t no_refset; uint8_t no_refset;
@ -189,6 +168,9 @@ typedef struct {
/* The index of header table to toggle off the entry from reference /* The index of header table to toggle off the entry from reference
set at the end of decompression. */ set at the end of decompression. */
size_t end_headers_index; size_t end_headers_index;
/* The maximum header table size the inflater supports. This is the
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
size_t settings_hd_table_bufsize_max;
nghttp2_hd_opcode opcode; nghttp2_hd_opcode opcode;
nghttp2_hd_inflate_state state; nghttp2_hd_inflate_state state;
/* nonzero if string is huffman encoded */ /* nonzero if string is huffman encoded */
@ -230,8 +212,7 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater);
nghttp2_hd_side side);
/* /*
* Initializes |deflater| for deflating name/values pairs. * Initializes |deflater| for deflating name/values pairs.
@ -247,7 +228,6 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater,
* Out of memory. * Out of memory.
*/ */
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max); size_t deflate_hd_table_bufsize_max);
/* /*
@ -259,8 +239,7 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater);
nghttp2_hd_side side);
/* /*
* Deallocates any resources allocated for |deflater|. * Deallocates any resources allocated for |deflater|.
@ -282,10 +261,11 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
uint8_t no_refset); uint8_t no_refset);
/* /*
* Changes header table size in |context|. This may trigger eviction * Changes header table size of the |deflater|. This may trigger
* in the dynamic table. * eviction in the dynamic table.
* *
* This function can be used for deflater and inflater. * The |settings_hd_table_bufsize_max| should be the value received in
* SETTINGS_HEADER_TABLE_SIZE.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -293,8 +273,25 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_hd_change_table_size(nghttp2_hd_context *context, int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t hd_table_bufsize_max); size_t settings_hd_table_bufsize_max);
/*
* Changes header table size in the |inflater|. This may trigger
* eviction in the dynamic table.
*
* The |settings_hd_table_bufsize_max| should be the value transmitted
* in SETTINGS_HEADER_TABLE_SIZE.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t settings_hd_table_bufsize_max);
/* /*
* Deflates the |nva|, which has the |nvlen| name/value pairs, into * Deflates the |nva|, which has the |nvlen| name/value pairs, into
@ -379,14 +376,16 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index, size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing, int inc_indexing);
nghttp2_hd_side side);
/* For unittesting purpose */ /* For unittesting purpose */
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv, size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing, int inc_indexing);
nghttp2_hd_side side);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size);
/* For unittesting purpose */ /* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
@ -395,37 +394,30 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
/* Huffman encoding/decoding functions */ /* Huffman encoding/decoding functions */
/* /*
* Counts the required bytes to encode |src| with length |len|. If * Counts the required bytes to encode |src| with length |len|.
* |side| is NGHTTP2_HD_SIDE_REQUEST, the request huffman code table
* is used. Otherwise, the response code table is used.
* *
* This function returns the number of required bytes to encode given * This function returns the number of required bytes to encode given
* data, including padding of prefix of terminal symbol code. This * data, including padding of prefix of terminal symbol code. This
* function always succeeds. * function always succeeds.
*/ */
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len, size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
nghttp2_hd_side side);
/* /*
* Encodes the given data |src| with length |srclen| to the given * Encodes the given data |src| with length |srclen| to the given
* memory location pointed by |dest|, allocated at lest |destlen| * memory location pointed by |dest|, allocated at lest |destlen|
* bytes. The caller is responsible to specify |destlen| at least the * bytes. The caller is responsible to specify |destlen| at least the
* length that nghttp2_hd_huff_encode_count() returns. If |side| is * length that nghttp2_hd_huff_encode_count() returns.
* NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* used. Otherwise, the response code table is used.
* *
* This function returns the number of written bytes, including * This function returns the number of written bytes, including
* padding of prefix of terminal symbol code. This return value is * padding of prefix of terminal symbol code. This return value is
* exactly the same with the return value of * exactly the same with the return value of
* nghttp2_hd_huff_encode_count() if it is given with the same |src|, * nghttp2_hd_huff_encode_count() if it is given with the same |src|
* |srclen|, and |side|. This function always succeeds. * and |srclen|. This function always succeeds.
*/ */
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen, ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen, const uint8_t *src, size_t srclen);
nghttp2_hd_side side);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx, void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
nghttp2_hd_side side);
/* /*
* Decodes the given data |src| with length |srclen|. The |ctx| must * Decodes the given data |src| with length |srclen|. The |ctx| must
@ -453,4 +445,4 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buffer *dest, nghttp2_buffer *dest,
const uint8_t *src, size_t srclen, int final); const uint8_t *src, size_t srclen, int final);
#endif /* NGHTTP2_HD_COMP_H */ #endif /* NGHTTP2_HD_H */

View File

@ -30,11 +30,8 @@
#include "nghttp2_hd.h" #include "nghttp2_hd.h"
extern const nghttp2_huff_sym req_huff_sym_table[]; extern const nghttp2_huff_sym huff_sym_table[];
extern const nghttp2_huff_decode req_huff_decode_table[][16]; extern const nghttp2_huff_decode huff_decode_table[][16];
extern const nghttp2_huff_sym res_huff_sym_table[];
extern const nghttp2_huff_decode res_huff_decode_table[][16];
/* /*
* Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits| * Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits|
@ -65,18 +62,11 @@ static size_t huff_encode_sym(uint8_t **dest_ptr, size_t rembits,
return rembits; return rembits;
} }
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len, size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len)
nghttp2_hd_side side)
{ {
size_t i; size_t i;
size_t nbits = 0; size_t nbits = 0;
const nghttp2_huff_sym *huff_sym_table;
if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table;
} else {
huff_sym_table = res_huff_sym_table;
}
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
nbits += huff_sym_table[src[i]].nbits; nbits += huff_sym_table[src[i]].nbits;
} }
@ -85,19 +75,12 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len,
} }
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen, ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen, const uint8_t *src, size_t srclen)
nghttp2_hd_side side)
{ {
int rembits = 8; int rembits = 8;
uint8_t *dest_first = dest; uint8_t *dest_first = dest;
size_t i; size_t i;
const nghttp2_huff_sym *huff_sym_table;
if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table;
} else {
huff_sym_table = res_huff_sym_table;
}
for(i = 0; i < srclen; ++i) { for(i = 0; i < srclen; ++i) {
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]]; const nghttp2_huff_sym *sym = &huff_sym_table[src[i]];
if(rembits == 8) { if(rembits == 8) {
@ -114,14 +97,8 @@ ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
return dest - dest_first; return dest - dest_first;
} }
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx, void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx)
nghttp2_hd_side side)
{ {
if(side == NGHTTP2_HD_SIDE_REQUEST) {
ctx->huff_decode_table = req_huff_decode_table;
} else {
ctx->huff_decode_table = res_huff_decode_table;
}
ctx->state = 0; ctx->state = 0;
ctx->accept = 1; ctx->accept = 1;
} }
@ -137,7 +114,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
for(i = 0; i < srclen; ++i) { for(i = 0; i < srclen; ++i) {
uint8_t in = src[i] >> 4; uint8_t in = src[i] >> 4;
for(j = 0; j < 2; ++j) { for(j = 0; j < 2; ++j) {
const nghttp2_huff_decode *t = &ctx->huff_decode_table[ctx->state][in]; const nghttp2_huff_decode *t = &huff_decode_table[ctx->state][in];
if(t->state == -1) { if(t->state == -1) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }

View File

@ -52,7 +52,6 @@ typedef struct {
typedef nghttp2_huff_decode huff_decode_table_type[16]; typedef nghttp2_huff_decode huff_decode_table_type[16];
typedef struct { typedef struct {
const huff_decode_table_type *huff_decode_table;
/* Current huffman decoding state. We stripped leaf nodes, so the /* Current huffman decoding state. We stripped leaf nodes, so the
value range is [0..255], inclusive. */ value range is [0..255], inclusive. */
uint8_t state; uint8_t state;

File diff suppressed because it is too large Load Diff

View File

@ -201,7 +201,7 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
const nghttp2_opt_set *opt_set) const nghttp2_opt_set *opt_set)
{ {
int r; int r;
nghttp2_hd_side side_deflate, side_inflate;
*session_ptr = malloc(sizeof(nghttp2_session)); *session_ptr = malloc(sizeof(nghttp2_session));
if(*session_ptr == NULL) { if(*session_ptr == NULL) {
r = NGHTTP2_ERR_NOMEM; r = NGHTTP2_ERR_NOMEM;
@ -236,17 +236,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
if(server) { if(server) {
(*session_ptr)->server = 1; (*session_ptr)->server = 1;
side_deflate = NGHTTP2_HD_SIDE_RESPONSE;
side_inflate = NGHTTP2_HD_SIDE_REQUEST;
} else {
side_deflate = NGHTTP2_HD_SIDE_REQUEST;
side_inflate = NGHTTP2_HD_SIDE_RESPONSE;
} }
r = nghttp2_hd_deflate_init(&(*session_ptr)->hd_deflater, side_deflate); r = nghttp2_hd_deflate_init(&(*session_ptr)->hd_deflater);
if(r != 0) { if(r != 0) {
goto fail_hd_deflater; goto fail_hd_deflater;
} }
r = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, side_inflate); r = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater);
if(r != 0) { if(r != 0) {
goto fail_hd_inflater; goto fail_hd_inflater;
} }
@ -2708,7 +2703,7 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
header_table_size > NGHTTP2_MAX_HEADER_TABLE_SIZE) { header_table_size > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
rv = nghttp2_hd_change_table_size(&session->hd_inflater.ctx, rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater,
header_table_size); header_table_size);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
@ -2791,7 +2786,7 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
return nghttp2_session_handle_invalid_connection return nghttp2_session_handle_invalid_connection
(session, frame, NGHTTP2_COMPRESSION_ERROR); (session, frame, NGHTTP2_COMPRESSION_ERROR);
} }
rv = nghttp2_hd_change_table_size(&session->hd_deflater.ctx, rv = nghttp2_hd_deflate_change_table_size(&session->hd_deflater,
entry->value); entry->value);
if(rv != 0) { if(rv != 0) {
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {

View File

@ -45,10 +45,6 @@ cdef extern from 'nghttp2_hd.h':
# This is macro # This is macro
int NGHTTP2_HD_ENTRY_OVERHEAD int NGHTTP2_HD_ENTRY_OVERHEAD
ctypedef enum nghttp2_hd_side:
NGHTTP2_HD_SIDE_REQUEST
NGHTTP2_HD_SIDE_RESPONSE
ctypedef enum nghttp2_hd_flags: ctypedef enum nghttp2_hd_flags:
NGHTTP2_HD_FLAG_REFSET NGHTTP2_HD_FLAG_REFSET
@ -73,12 +69,9 @@ cdef extern from 'nghttp2_hd.h':
nghttp2_hd_context ctx nghttp2_hd_context ctx
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
nghttp2_hd_side side,
size_t deflate_hd_table_bufsize_max) size_t deflate_hd_table_bufsize_max)
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater)
nghttp2_hd_side side)
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater)
@ -87,7 +80,10 @@ cdef extern from 'nghttp2_hd.h':
void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater,
uint8_t no_refset) uint8_t no_refset)
int nghttp2_hd_change_table_size(nghttp2_hd_context *context, int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t hd_table_bufsize_max)
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t hd_table_bufsize_max) size_t hd_table_bufsize_max)
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,

View File

@ -13,12 +13,7 @@ from binascii import a2b_hex
import nghttp2 import nghttp2
def testsuite(testdata): def testsuite(testdata):
if testdata['context'] == 'request': inflater = nghttp2.HDInflater()
side = nghttp2.HD_SIDE_REQUEST
else:
side = nghttp2.HD_SIDE_RESPONSE
inflater = nghttp2.HDInflater(side)
for casenum, item in enumerate(testdata['cases']): for casenum, item in enumerate(testdata['cases']):
if 'header_table_size' in item: if 'header_table_size' in item:
@ -47,7 +42,7 @@ def testsuite(testdata):
if __name__ == '__main__': if __name__ == '__main__':
for filename in sys.argv[1:]: for filename in sys.argv[1:]:
sys.stderr.write('{}\n'.format(filename)) sys.stderr.write('{}: '.format(filename))
with open(filename) as f: with open(filename) as f:
input = f.read() input = f.read()
testsuite(json.loads(input)) testsuite(json.loads(input))

View File

@ -14,11 +14,6 @@ from binascii import b2a_hex
import nghttp2 import nghttp2
def testsuite(testdata, filename, outdir, table_size, deflate_table_size): def testsuite(testdata, filename, outdir, table_size, deflate_table_size):
if testdata['context'] == 'request':
side = nghttp2.HD_SIDE_REQUEST
else:
side = nghttp2.HD_SIDE_RESPONSE
res = { res = {
'draft':5, 'context': testdata['context'], 'draft':5, 'context': testdata['context'],
'description': '''\ 'description': '''\
@ -29,7 +24,7 @@ original. We make some headers not indexing at all, but this does not always \
result in less bits on the wire.''' result in less bits on the wire.'''
} }
cases = [] cases = []
deflater = nghttp2.HDDeflater(side, deflate_table_size) deflater = nghttp2.HDDeflater(deflate_table_size)
deflater.change_table_size(table_size) deflater.change_table_size(table_size)
for casenum, item in enumerate(testdata['cases']): for casenum, item in enumerate(testdata['cases']):
outitem = { outitem = {

View File

@ -26,9 +26,6 @@ from libc.stdlib cimport malloc, free
from libc.string cimport memcpy, memset from libc.string cimport memcpy, memset
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t
HD_SIDE_REQUEST = cnghttp2.NGHTTP2_HD_SIDE_REQUEST
HD_SIDE_RESPONSE = cnghttp2.NGHTTP2_HD_SIDE_RESPONSE
HD_DEFLATE_HD_TABLE_BUFSIZE_MAX = 4096 HD_DEFLATE_HD_TABLE_BUFSIZE_MAX = 4096
HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD
@ -45,12 +42,6 @@ class HDTableEntry:
def space(self): def space(self):
return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD
cdef _change_table_size(cnghttp2.nghttp2_hd_context *ctx, hd_table_bufsize_max):
cdef int rv
rv = cnghttp2.nghttp2_hd_change_table_size(ctx, hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx): cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
cdef int length = ctx.hd_table.len cdef int length = ctx.hd_table.len
cdef cnghttp2.nghttp2_hd_entry *entry cdef cnghttp2.nghttp2_hd_entry *entry
@ -65,35 +56,25 @@ cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx):
return res return res
cdef _get_pybytes(uint8_t *b, uint16_t blen): cdef _get_pybytes(uint8_t *b, uint16_t blen):
# While the |blen| is positive, the |b| could be NULL. This is return b[:blen]
# because deflater may deallocate the byte strings its local table
# space.
if b == NULL and blen > 0:
val = None
else:
val = b[:blen]
return val
cdef class HDDeflater: cdef class HDDeflater:
'''Performs header compression. The header compression algorithm has '''Performs header compression. The constructor takes
to know the header set to be compressed is request headers or |hd_table_bufsize_max| parameter, which limits the usage of header
response headers. It is indicated by |side| parameter in the table in the given amount of bytes. This is necessary because the
constructor. The constructor also takes |hd_table_bufsize_max| header compressor and decompressor has to share the same amount of
parameter, which limits the usage of header table in the given header table and the decompressor decides that number. The
amount of bytes. This is necessary because the header compressor compressor may not want to use all header table size because of
and decompressor has to share the same amount of header table and limited memory availability. In that case, the
the decompressor decides that number. The compressor may not want |hd_table_bufsize_max| can be used to cap the upper limit of table
to use all header table size because of limited memory size whatever the header table size is chosen by the decompressor.
availability. In that case, the |hd_table_bufsize_max| can be used The default value of |hd_table_bufsize_max| is 4096 bytes.
to cap the upper limit of talbe size whatever the header table
size is chosen. The default value of |hd_table_bufsize_max| is
4096 bytes.
The following example shows how to compress request header sets: The following example shows how to compress request header sets:
import binascii, nghttp2 import binascii, nghttp2
deflater = nghttp2.HDDeflater(nghttp2.HD_SIDE_REQUEST) deflater = nghttp2.HDDeflater()
res = deflater.deflate([(b'foo', b'bar'), res = deflater.deflate([(b'foo', b'bar'),
(b'baz', b'buz')]) (b'baz', b'buz')])
print(binascii.b2a_hex(res)) print(binascii.b2a_hex(res))
@ -102,17 +83,13 @@ cdef class HDDeflater:
cdef cnghttp2.nghttp2_hd_deflater _deflater cdef cnghttp2.nghttp2_hd_deflater _deflater
def __cinit__(self, side, def __cinit__(self,
hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX): hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX):
rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater, side, rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater,
hd_table_bufsize_max) hd_table_bufsize_max)
if rv != 0: if rv != 0:
raise Exception(_strerror(rv)) raise Exception(_strerror(rv))
def __init__(self, side,
hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX):
super(HDDeflater, self).__init__()
def __dealloc__(self): def __dealloc__(self):
cnghttp2.nghttp2_hd_deflate_free(&self._deflater) cnghttp2.nghttp2_hd_deflate_free(&self._deflater)
@ -165,7 +142,11 @@ cdef class HDDeflater:
An exception will be raised on error. An exception will be raised on error.
''' '''
_change_table_size(&self._deflater.ctx, hd_table_bufsize_max) cdef int rv
rv = cnghttp2.nghttp2_hd_deflate_change_table_size(&self._deflater,
hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
def get_hd_table(self,): def get_hd_table(self,):
'''Returns copy of current dynamic header table.''' '''Returns copy of current dynamic header table.'''
@ -177,7 +158,7 @@ cdef class HDInflater:
The following example shows how to compress request header sets: The following example shows how to compress request header sets:
data = b'0082c5ad82bd0f000362617a0362757a' data = b'0082c5ad82bd0f000362617a0362757a'
inflater = nghttp2.HDInflater(nghttp2.HD_SIDE_REQUEST) inflater = nghttp2.HDInflater()
hdrs = inflater.inflate(data) hdrs = inflater.inflate(data)
print(hdrs) print(hdrs)
@ -185,14 +166,11 @@ cdef class HDInflater:
cdef cnghttp2.nghttp2_hd_inflater _inflater cdef cnghttp2.nghttp2_hd_inflater _inflater
def __cinit__(self, side): def __cinit__(self):
rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater, side) rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater)
if rv != 0: if rv != 0:
raise Exception(_strerror(rv)) raise Exception(_strerror(rv))
def __init__(self, side):
super(HDInflater, self).__init__()
def __dealloc__(self): def __dealloc__(self):
cnghttp2.nghttp2_hd_inflate_free(&self._inflater) cnghttp2.nghttp2_hd_inflate_free(&self._inflater)
@ -231,7 +209,11 @@ cdef class HDInflater:
An exception will be raised on error. An exception will be raised on error.
''' '''
_change_table_size(&self._inflater.ctx, hd_table_bufsize_max) cdef int rv
rv = cnghttp2.nghttp2_hd_inflate_change_table_size(&self._inflater,
hd_table_bufsize_max)
if rv != 0:
raise Exception(_strerror(rv))
def get_hd_table(self): def get_hd_table(self):
'''Returns copy of current dynamic header table.''' '''Returns copy of current dynamic header table.'''
@ -255,5 +237,5 @@ def print_hd_table(hdtable):
print('[{}] (s={}) (r={}) {}: {}'\ print('[{}] (s={}) (r={}) {}: {}'\
.format(idx, entry.space(), .format(idx, entry.space(),
'y' if entry.ref else 'n', 'y' if entry.ref else 'n',
'**DEALLOCATED**' if entry.name is None else entry.name.decode('utf-8'), entry.name.decode('utf-8'),
'**DEALLOCATED**' if entry.value is None else entry.value.decode('utf-8'))) entry.value.decode('utf-8')))

View File

@ -27,11 +27,7 @@
static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len) static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len)
{ {
if(val == NULL && len > 0) {
json_object_set_new(jent, key, json_string("**DEALLOCATED**"));
} else {
json_object_set_new(jent, key, json_pack("s#", val, len)); json_object_set_new(jent, key, json_pack("s#", val, len));
}
} }
json_t* dump_header_table(nghttp2_hd_context *context) json_t* dump_header_table(nghttp2_hd_context *context)
@ -58,12 +54,6 @@ json_t* dump_header_table(nghttp2_hd_context *context)
json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize)); json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize));
json_object_set_new(obj, "max_size", json_object_set_new(obj, "max_size",
json_integer(context->hd_table_bufsize_max)); json_integer(context->hd_table_bufsize_max));
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
json_object_set_new(obj, "deflate_size",
json_integer(context->deflate_hd_table_bufsize));
json_object_set_new(obj, "max_deflate_size",
json_integer(context->deflate_hd_table_bufsize_max));
}
return obj; return obj;
} }
@ -93,13 +83,11 @@ json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen)
return headers; return headers;
} }
void output_json_header(int side) void output_json_header(void)
{ {
printf("{\n" printf("{\n"
" \"context\": \"%s\",\n"
" \"cases\":\n" " \"cases\":\n"
" [\n", " [\n");
(side == NGHTTP2_HD_SIDE_REQUEST ? "request" : "response"));
} }
void output_json_footer(void) void output_json_footer(void)

View File

@ -40,7 +40,7 @@ json_t* dump_header(const uint8_t *name, size_t namelen,
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen); json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen);
void output_json_header(int side); void output_json_header(void);
void output_json_footer(void); void output_json_footer(void);

View File

@ -44,7 +44,6 @@
typedef struct { typedef struct {
size_t table_size; size_t table_size;
size_t deflate_table_size; size_t deflate_table_size;
nghttp2_hd_side side;
int http1text; int http1text;
int dump_header_table; int dump_header_table;
int no_refset; int no_refset;
@ -174,11 +173,11 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
return 0; return 0;
} }
static void init_deflater(nghttp2_hd_deflater *deflater, nghttp2_hd_side side) static void init_deflater(nghttp2_hd_deflater *deflater)
{ {
nghttp2_hd_deflate_init2(deflater, side, config.deflate_table_size); nghttp2_hd_deflate_init2(deflater, config.deflate_table_size);
nghttp2_hd_deflate_set_no_refset(deflater, config.no_refset); nghttp2_hd_deflate_set_no_refset(deflater, config.no_refset);
nghttp2_hd_change_table_size(&deflater->ctx, config.table_size); nghttp2_hd_deflate_change_table_size(deflater, config.table_size);
} }
static void deinit_deflater(nghttp2_hd_deflater *deflater) static void deinit_deflater(nghttp2_hd_deflater *deflater)
@ -193,19 +192,12 @@ static int perform(void)
json_error_t error; json_error_t error;
size_t len; size_t len;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error); json = json_loadf(stdin, 0, &error);
if(json == NULL) { if(json == NULL) {
fprintf(stderr, "JSON loading failed\n"); fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(strcmp("request", json_string_value(json_object_get(json, "context")))
== 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases"); cases = json_object_get(json, "cases");
if(cases == NULL) { if(cases == NULL) {
fprintf(stderr, "Missing 'cases' key in root object\n"); fprintf(stderr, "Missing 'cases' key in root object\n");
@ -215,8 +207,8 @@ static int perform(void)
fprintf(stderr, "'cases' must be JSON array\n"); fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
init_deflater(&deflater, side); init_deflater(&deflater);
output_json_header(side); output_json_header();
len = json_array_size(cases); len = json_array_size(cases);
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i); json_t *obj = json_array_get(cases, i);
@ -244,8 +236,8 @@ static int perform_from_http1text(void)
nghttp2_nv nva[256]; nghttp2_nv nva[256];
int seq = 0; int seq = 0;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
init_deflater(&deflater, config.side); init_deflater(&deflater);
output_json_header(config.side); output_json_header();
for(;;) { for(;;) {
size_t nvlen = 0; size_t nvlen = 0;
int end = 0; int end = 0;
@ -355,10 +347,6 @@ static void print_help(void)
"The output of this program can be used as input for inflatehd.\n" "The output of this program can be used as input for inflatehd.\n"
"\n" "\n"
"OPTIONS:\n" "OPTIONS:\n"
" -r, --response Use response compression context instead of\n"
" request if -t is used. For JSON input, it is\n"
" determined by inspecting \"context\" key in\n"
" root JSON object.\n"
" -t, --http1text Use HTTP/1 style header field text as input.\n" " -t, --http1text Use HTTP/1 style header field text as input.\n"
" Each header set is delimited by single empty\n" " Each header set is delimited by single empty\n"
" line.\n" " line.\n"
@ -377,7 +365,6 @@ static void print_help(void)
} }
static struct option long_options[] = { static struct option long_options[] = {
{"response", no_argument, NULL, 'r'},
{"http1text", no_argument, NULL, 't'}, {"http1text", no_argument, NULL, 't'},
{"table-size", required_argument, NULL, 's'}, {"table-size", required_argument, NULL, 's'},
{"deflate-table-size", required_argument, NULL, 'S'}, {"deflate-table-size", required_argument, NULL, 'S'},
@ -390,7 +377,6 @@ int main(int argc, char **argv)
{ {
char *end; char *end;
config.side = NGHTTP2_HD_SIDE_REQUEST;
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
config.deflate_table_size = NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; config.deflate_table_size = NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
config.http1text = 0; config.http1text = 0;
@ -398,15 +384,11 @@ int main(int argc, char **argv)
config.no_refset = 0; config.no_refset = 0;
while(1) { while(1) {
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "S:cdhrs:t", long_options, &option_index); int c = getopt_long(argc, argv, "S:cdhs:t", long_options, &option_index);
if(c == -1) { if(c == -1) {
break; break;
} }
switch(c) { switch(c) {
case 'r':
/* --response */
config.side = NGHTTP2_HD_SIDE_RESPONSE;
break;
case 'h': case 'h':
print_help(); print_help();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);

View File

@ -42,7 +42,6 @@
#include "comp_helper.h" #include "comp_helper.h"
typedef struct { typedef struct {
size_t table_size;
int dump_header_table; int dump_header_table;
} inflate_config; } inflate_config;
@ -110,7 +109,7 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
seq); seq);
return -1; return -1;
} }
rv = nghttp2_hd_change_table_size(&inflater->ctx, rv = nghttp2_hd_inflate_change_table_size(inflater,
json_integer_value(table_size)); json_integer_value(table_size));
if(rv != 0) { if(rv != 0) {
fprintf(stderr, fprintf(stderr,
@ -163,19 +162,12 @@ static int perform(void)
json_t *json, *cases; json_t *json, *cases;
json_error_t error; json_error_t error;
size_t len; size_t len;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error); json = json_loadf(stdin, 0, &error);
if(json == NULL) { if(json == NULL) {
fprintf(stderr, "JSON loading failed\n"); fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(strcmp("request", json_string_value(json_object_get(json, "context")))
== 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases"); cases = json_object_get(json, "cases");
if(cases == NULL) { if(cases == NULL) {
fprintf(stderr, "Missing 'cases' key in root object\n"); fprintf(stderr, "Missing 'cases' key in root object\n");
@ -185,10 +177,8 @@ static int perform(void)
fprintf(stderr, "'cases' must be JSON array\n"); fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
nghttp2_hd_inflate_init(&inflater, side); nghttp2_hd_inflate_init(&inflater);
nghttp2_hd_change_table_size(&inflater.ctx, config.table_size); output_json_header();
output_json_header(side);
len = json_array_size(cases); len = json_array_size(cases);
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i); json_t *obj = json_array_get(cases, i);
@ -241,29 +231,21 @@ static void print_help(void)
"The output of this program can be used as input for deflatehd.\n" "The output of this program can be used as input for deflatehd.\n"
"\n" "\n"
"OPTIONS:\n" "OPTIONS:\n"
" -s, --table-size=<N>\n"
" Set dynamic table size. In the HPACK\n"
" specification, this value is denoted by\n"
" SETTINGS_HEADER_TABLE_SIZE.\n"
" Default: 4096\n"
" -d, --dump-header-table\n" " -d, --dump-header-table\n"
" Output dynamic header table.\n"); " Output dynamic header table.\n");
} }
static struct option long_options[] = { static struct option long_options[] = {
{"table-size", required_argument, NULL, 's'},
{"dump-header-table", no_argument, NULL, 'd'}, {"dump-header-table", no_argument, NULL, 'd'},
{NULL, 0, NULL, 0 } {NULL, 0, NULL, 0 }
}; };
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *end;
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
config.dump_header_table = 0; config.dump_header_table = 0;
while(1) { while(1) {
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "dhs:", long_options, &option_index); int c = getopt_long(argc, argv, "dh", long_options, &option_index);
if(c == -1) { if(c == -1) {
break; break;
} }
@ -271,15 +253,6 @@ int main(int argc, char **argv)
case 'h': case 'h':
print_help(); print_help();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 's':
/* --table-size */
errno = 0;
config.table_size = strtoul(optarg, &end, 10);
if(errno == ERANGE || *end != '\0') {
fprintf(stderr, "-s: Bad option value\n");
exit(EXIT_FAILURE);
}
break;
case 'd': case 'd':
/* --dump-header-table */ /* --dump-header-table */
config.dump_header_table = 1; config.dump_header_table = 1;

View File

@ -225,8 +225,6 @@ int main(int argc, char* argv[])
test_nghttp2_hd_deflate_same_indexed_repr) || test_nghttp2_hd_deflate_same_indexed_repr) ||
!CU_add_test(pSuite, "hd_deflate_common_header_eviction", !CU_add_test(pSuite, "hd_deflate_common_header_eviction",
test_nghttp2_hd_deflate_common_header_eviction) || test_nghttp2_hd_deflate_common_header_eviction) ||
!CU_add_test(pSuite, "hd_deflate_deflate_buffer",
test_nghttp2_hd_deflate_deflate_buffer) ||
!CU_add_test(pSuite, "hd_deflate_clear_refset", !CU_add_test(pSuite, "hd_deflate_clear_refset",
test_nghttp2_hd_deflate_clear_refset) || test_nghttp2_hd_deflate_clear_refset) ||
!CU_add_test(pSuite, "hd_inflate_indname_noinc", !CU_add_test(pSuite, "hd_inflate_indname_noinc",

View File

@ -82,8 +82,8 @@ void test_nghttp2_frame_pack_headers()
ssize_t nv_offset; ssize_t nv_offset;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
nva = headers(); nva = headers();
nvlen = HEADERS_LENGTH; nvlen = HEADERS_LENGTH;
@ -171,7 +171,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
} }
nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen); nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nghttp2_frame_headers_init(&frame, nghttp2_frame_headers_init(&frame,
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007, 1000000007,
@ -269,8 +269,8 @@ void test_nghttp2_frame_pack_push_promise()
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_RESPONSE); nghttp2_hd_deflate_init(&deflater);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); nghttp2_hd_inflate_init(&inflater);
nva = headers(); nva = headers();
nvlen = HEADERS_LENGTH; nvlen = HEADERS_LENGTH;

View File

@ -59,8 +59,8 @@ void test_nghttp2_hd_deflate(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST)); CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1,
sizeof(nva1)/sizeof(nghttp2_nv)); sizeof(nva1)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
@ -142,8 +142,8 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST)); CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
/* Encode 2 same headers. cookie:alpha is not in the reference set, /* Encode 2 same headers. cookie:alpha is not in the reference set,
so first emit literal repr and then 2 emits of indexed repr. */ so first emit literal repr and then 2 emits of indexed repr. */
@ -198,8 +198,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nva[i].valuelen = sizeof(value); nva[i].valuelen = sizeof(value);
} }
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
/* First emit "h1: ..." to put it in the reference set (index /* First emit "h1: ..." to put it in the reference set (index
= 0). */ = 0). */
@ -236,174 +236,6 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
void test_nghttp2_hd_deflate_deflate_buffer(void)
{
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
size_t i;
ssize_t blocklen;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_nv nva1[] = { MAKE_NV("k1", "v1"), /* 36 */
MAKE_NV("k10", "v10"), /* 38 */
MAKE_NV("k100", "v100"), /* 40 */
MAKE_NV("k1000", "v1000") /* 42 */
}; /* Total: 156 */
nghttp2_nv nva2[] = { MAKE_NV("k10", "v10"), /* 38 */
MAKE_NV("k1", "v1") /* 36 */
};
nghttp2_nv nv3;
uint8_t val[256];
nghttp2_nv nva4[] = { MAKE_NV(":method", "GET"),
MAKE_NV(":scheme", "http")
};
nghttp2_hd_entry *ent;
nva_out out;
nva_out_init(&out);
memset(val, 'a', sizeof(val));
nv3.name = nv3.value = val;
nv3.namelen = nv3.valuelen = sizeof(val);
/* Check the case where entry from static table is inserted to
dynamic header table. And it is out of deflate header table
size. */
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 32);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
nva4, ARRLEN(nva4));
CU_ASSERT(blocklen > 0);
/* Now header table should look like this:
*
* 0: :scheme, http (-)
* 1: :method, GET (-)
*
* name/value of all entries must be NULL.
*/
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(0 == deflater.ctx.deflate_hd_table_bufsize);
for(i = 0; i < 2; ++i) {
ent = nghttp2_hd_table_get(&deflater.ctx, i);
CU_ASSERT(ent->nv.name == NULL);
CU_ASSERT(ent->nv.value == NULL);
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
}
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva4, out.nva, 2);
nva_out_reset(&out);
nghttp2_hd_deflate_free(&deflater);
nghttp2_hd_inflate_free(&inflater);
/* 156 buffer size can hold all headers in deflate region */
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 156);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
nva1, ARRLEN(nva1));
CU_ASSERT(blocklen > 0);
/* Now header table should look like this:
*
* 0: k1000, v100
* 1: k100, v100
* 2: k10, v10
* 3: k1, v1
*/
CU_ASSERT(4 == deflater.ctx.hd_table.len);
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
for(i = 0; i < 4; ++i) {
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL);
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL);
}
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 156));
CU_ASSERT(4 == deflater.ctx.hd_table.len);
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, &nv3, 1);
CU_ASSERT(blocklen > 0);
/* Now header table should be unchanged, because we don't index
large header */
CU_ASSERT(4 == deflater.ctx.hd_table.len);
CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize);
nghttp2_hd_deflate_free(&deflater);
/* Check more complex use case */
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 155);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
nva1, ARRLEN(nva1));
CU_ASSERT(blocklen > 0);
/* Now header table should look like this:
*
* 0: k1000, v100 (R)
* 1: k100, v100 (R)
* 2: k10, v10 (R)
* 3: k1, v1 (-) <- name, value must be NULL and not in reference set
*
* But due to the deflate table size limit, name/value of index=3 must
* be NULL.
*/
CU_ASSERT(4 == deflater.ctx.hd_table.len);
CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(120 == deflater.ctx.deflate_hd_table_bufsize);
for(i = 0; i < 3; ++i) {
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL);
CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL);
}
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
CU_ASSERT(ent->nv.name == NULL);
CU_ASSERT(ent->nv.value == NULL);
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(4 == out.nvlen);
assert_nv_equal(nva1, out.nva, 4);
nva_out_reset(&out);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
nva2, ARRLEN(nva2));
CU_ASSERT(blocklen > 0);
/* Now header table should look like this:
*
* 0: k1, v1 (R)
* 1: k1000, v100 (R)
* 2: k100, v100 (R)
* 3: k10, v10 (-) <- name, value must be NULL
* 4: k1, v1 (-) <- name, value must be NULL
*/
CU_ASSERT(5 == deflater.ctx.hd_table.len);
CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen);
CU_ASSERT(118 == deflater.ctx.deflate_hd_table_bufsize);
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
ent = nghttp2_hd_table_get(&deflater.ctx, 3);
CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(2 == out.nvlen);
/* Sort before comparison */
nghttp2_nv_array_sort(nva2, 2);
assert_nv_equal(nva2, out.nva, 2);
nva_out_reset(&out);
free(buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
void test_nghttp2_hd_deflate_clear_refset(void) void test_nghttp2_hd_deflate_clear_refset(void)
{ {
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
@ -419,10 +251,10 @@ void test_nghttp2_hd_deflate_clear_refset(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, nghttp2_hd_deflate_init2(&deflater,
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE); NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
nghttp2_hd_deflate_set_no_refset(&deflater, 1); nghttp2_hd_deflate_set_no_refset(&deflater, 1);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < 2; ++i) { for(i = 0; i < 2; ++i) {
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0,
@ -457,14 +289,13 @@ void test_nghttp2_hd_inflate_indname_noinc(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) { for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0; offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
nv[i].value, nv[i].valuelen, nv[i].value, nv[i].valuelen,
0, 0));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -488,11 +319,10 @@ void test_nghttp2_hd_inflate_indname_inc(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
nv.value, nv.valuelen, 1, nv.value, nv.valuelen, 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -517,21 +347,17 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
memset(value, '0', sizeof(value)); memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13,
value, sizeof(value), 1, value, sizeof(value), 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14,
value, sizeof(value), 1, value, sizeof(value), 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15,
value, sizeof(value), 1, value, sizeof(value), 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16,
value, sizeof(value), 1, value, sizeof(value), 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
@ -569,12 +395,11 @@ void test_nghttp2_hd_inflate_newname_noinc(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) { for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0; offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv[i], 0, &nv[i], 0));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -598,11 +423,10 @@ void test_nghttp2_hd_inflate_newname_inc(void)
nva_out out; nva_out out;
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1, &nv, 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -635,11 +459,10 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
nv.value = value; nv.value = value;
nv.valuelen = sizeof(value); nv.valuelen = sizeof(value);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1, &nv, 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -663,8 +486,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
offset = 0; offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1, &nv, 1));
NGHTTP2_HD_SIDE_REQUEST));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -690,7 +512,7 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void)
buf[2] = 'x'; buf[2] = 'x';
buf[3] = 0x80; buf[3] = 0x80;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(4 == inflate_hd(&inflater, &out, buf, 4)); CU_ASSERT(4 == inflate_hd(&inflater, &out, buf, 4));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
@ -706,35 +528,158 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void)
void test_nghttp2_hd_change_table_size(void) void test_nghttp2_hd_change_table_size(void)
{ {
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = { MAKE_NV(":method", "GET"), nghttp2_nv nva[] = { MAKE_NV(":method", "GET"),
MAKE_NV(":path", "/") }; MAKE_NV(":path", "/") };
uint8_t *buf = NULL; uint8_t *buf = NULL;
size_t buflen = 0; size_t buflen = 0;
ssize_t rv; ssize_t rv;
nva_out out;
size_t offset;
nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater);
nghttp2_hd_inflate_init(&inflater);
/* inflater changes notifies 8000 max header table size */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000));
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
/* This will emit encoding context update with header table size 4096 */
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
/* inflater changes header table size to 1024 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 1024));
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
/* inflater changes header table size to 0 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 0));
CU_ASSERT(127 == deflater.ctx.hd_table.mask);
CU_ASSERT(0 == deflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
CU_ASSERT(0 == inflater.ctx.hd_table.len);
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(0 == deflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
CU_ASSERT(0 == inflater.ctx.hd_table.len);
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
free(buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
/* Check table buffer is expanded */
buf = NULL;
buflen = 0;
nghttp2_hd_deflate_init2(&deflater, 8192);
nghttp2_hd_inflate_init(&inflater);
/* First inflater changes header table size to 8000 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000));
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST);
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 8000));
CU_ASSERT(255 == deflater.ctx.hd_table.mask); CU_ASSERT(255 == deflater.ctx.hd_table.mask);
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(255 == inflater.ctx.hd_table.mask);
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(rv > 0); CU_ASSERT(rv > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 16384)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
CU_ASSERT(511 == deflater.ctx.hd_table.mask); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383));
CU_ASSERT(255 == deflater.ctx.hd_table.mask);
CU_ASSERT(16383 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(511 == inflater.ctx.hd_table.mask);
CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(2 == deflater.ctx.deflate_hd_tablelen); CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(5 ==
deflater.ctx.hd_table.buffer[deflater.ctx.hd_table.first]
->nv.namelen);
CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 0)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv));
CU_ASSERT(511 == deflater.ctx.hd_table.mask); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.hd_table.len); CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen); CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
/* Lastly, check the error condition */
offset = 0;
rv = nghttp2_hd_emit_table_size(&buf, &buflen, &offset, 25600);
CU_ASSERT(rv == 0);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP ==
inflate_hd(&inflater, &out, buf, offset));
nva_out_reset(&out);
free(buf); free(buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -899,8 +844,8 @@ void test_nghttp2_hd_deflate_inflate(void)
MAKE_NV("x-cache-lookup", "HIT from alphabravo:3128"), MAKE_NV("x-cache-lookup", "HIT from alphabravo:3128"),
}; };
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
check_deflate_inflate(&deflater, &inflater, nv1, ARRLEN(nv1)); check_deflate_inflate(&deflater, &inflater, nv1, ARRLEN(nv1));
check_deflate_inflate(&deflater, &inflater, nv2, ARRLEN(nv2)); check_deflate_inflate(&deflater, &inflater, nv2, ARRLEN(nv2));

View File

@ -28,7 +28,6 @@
void test_nghttp2_hd_deflate(void); void test_nghttp2_hd_deflate(void);
void test_nghttp2_hd_deflate_same_indexed_repr(void); void test_nghttp2_hd_deflate_same_indexed_repr(void);
void test_nghttp2_hd_deflate_common_header_eviction(void); void test_nghttp2_hd_deflate_common_header_eviction(void);
void test_nghttp2_hd_deflate_deflate_buffer(void);
void test_nghttp2_hd_deflate_clear_refset(void); void test_nghttp2_hd_deflate_clear_refset(void);
void test_nghttp2_hd_inflate_indname_noinc(void); void test_nghttp2_hd_inflate_indname_noinc(void);
void test_nghttp2_hd_inflate_indname_inc(void); void test_nghttp2_hd_inflate_indname_inc(void);

View File

@ -363,7 +363,7 @@ void test_nghttp2_session_recv(void)
callbacks.on_frame_recv_callback = on_frame_recv_callback; callbacks.on_frame_recv_callback = on_frame_recv_callback;
user_data.df = &df; user_data.df = &df;
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
@ -446,7 +446,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
user_data.df = &df; user_data.df = &df;
user_data.invalid_frame_recv_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0;
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
NGHTTP2_PRI_DEFAULT, NULL, 0); NGHTTP2_PRI_DEFAULT, NULL, 0);
@ -491,7 +491,7 @@ void test_nghttp2_session_recv_invalid_frame(void)
user_data.df = &df; user_data.df = &df;
user_data.frame_send_cb_called = 0; user_data.frame_send_cb_called = 0;
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
NGHTTP2_PRI_DEFAULT, nva, nvlen); NGHTTP2_PRI_DEFAULT, nva, nvlen);
@ -690,7 +690,7 @@ void test_nghttp2_session_recv_continuation(void)
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
/* Make 1 HEADERS and insert CONTINUATION header */ /* Make 1 HEADERS and insert CONTINUATION header */
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
@ -746,7 +746,7 @@ void test_nghttp2_session_recv_continuation(void)
/* Expecting CONTINUATION, but get the other frame */ /* Expecting CONTINUATION, but get the other frame */
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
/* HEADERS without END_HEADERS flag */ /* HEADERS without END_HEADERS flag */
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
@ -803,7 +803,7 @@ void test_nghttp2_session_recv_premature_headers(void)
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
@ -867,7 +867,7 @@ void test_nghttp2_session_continue(void)
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_deflate_init(&deflater);
/* Make 2 HEADERS frames */ /* Make 2 HEADERS frames */
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
@ -2255,7 +2255,7 @@ void test_nghttp2_submit_request_without_data(void)
callbacks.send_callback = accumulator_send_callback; callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), &data_prd, NULL)); nva, ARRLEN(nva), &data_prd, NULL));
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
@ -2327,7 +2327,7 @@ void test_nghttp2_submit_response_without_data(void)
callbacks.send_callback = accumulator_send_callback; callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); nghttp2_hd_inflate_init(&inflater);
nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL); NGHTTP2_STREAM_OPENING, NULL);
@ -2499,7 +2499,7 @@ void test_nghttp2_submit_headers(void)
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_submit_headers(session, CU_ASSERT(0 == nghttp2_submit_headers(session,
NGHTTP2_FLAG_END_STREAM, NGHTTP2_FLAG_END_STREAM,
1, NGHTTP2_PRI_DEFAULT, 1, NGHTTP2_PRI_DEFAULT,