Experiment HPACK with upcoming changes

* remove substitution
* reversed insertion and removal from header table
* unified initial static table
This commit is contained in:
Tatsuhiro Tsujikawa 2013-10-12 21:49:01 +09:00
parent e85418f045
commit 8cf3731802
5 changed files with 252 additions and 473 deletions

View File

@ -26,11 +26,12 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include "nghttp2_frame.h" #include "nghttp2_frame.h"
#include "nghttp2_helper.h" #include "nghttp2_helper.h"
static const char *reqhd_table[] = { static const char *static_table[] = {
":scheme", "http", ":scheme", "http",
":scheme", "https", ":scheme", "https",
":host", "", ":host", "",
@ -61,10 +62,7 @@ static const char *reqhd_table[] = {
"proxy-authorization", "", "proxy-authorization", "",
"range", "", "range", "",
"via", "", "via", "",
NULL
};
static const char *reshd_table[] = {
":status", "200", ":status", "200",
"age", "", "age", "",
"cache-control", "", "cache-control", "",
@ -104,7 +102,7 @@ typedef struct {
size_t nvlen; size_t nvlen;
} nghttp2_nva_out; } nghttp2_nva_out;
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t index, uint8_t flags, int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags,
uint8_t *name, uint16_t namelen, uint8_t *name, uint16_t namelen,
uint8_t *value, uint16_t valuelen) uint8_t *value, uint16_t valuelen)
{ {
@ -139,7 +137,6 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t index, uint8_t flags,
ent->nv.namelen = namelen; ent->nv.namelen = namelen;
ent->nv.valuelen = valuelen; ent->nv.valuelen = valuelen;
ent->ref = 1; ent->ref = 1;
ent->index = index;
ent->flags = flags; ent->flags = flags;
return 0; return 0;
@ -162,29 +159,81 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent)
} }
} }
static int nghttp2_hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf,
size_t bufsize)
{
size_t size;
for(size = 1; size < bufsize; size <<= 1);
ringbuf->buffer = malloc(sizeof(nghttp2_hd_entry*)*size);
if(ringbuf->buffer == NULL) {
return NGHTTP2_ERR_NOMEM;
}
ringbuf->mask = size - 1;
ringbuf->first = 0;
ringbuf->len = 0;
return 0;
}
static nghttp2_hd_entry* nghttp2_hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf,
size_t index)
{
assert(index < ringbuf->len);
return ringbuf->buffer[(ringbuf->first + index) & ringbuf->mask];
}
static void nghttp2_hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf)
{
size_t i;
if(ringbuf == NULL) {
return;
}
for(i = 0; i < ringbuf->len; ++i) {
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(ringbuf, i);
--ent->ref;
nghttp2_hd_entry_free(ent);
free(ent);
}
free(ringbuf->buffer);
}
static size_t nghttp2_hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf,
nghttp2_hd_entry *ent)
{
assert(ringbuf->len + 1 <= ringbuf->mask);
ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent;
++ringbuf->len;
return 0;
}
static void nghttp2_hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf)
{
assert(ringbuf->len > 0);
--ringbuf->len;
}
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) nghttp2_hd_side side)
{ {
int i; int i;
const char **ini_table; int rv;
context->role = role; context->role = role;
context->bad = 0; context->bad = 0;
context->hd_table = malloc(sizeof(nghttp2_hd_entry*)* rv = nghttp2_hd_ringbuf_init(&context->hd_table,
NGHTTP2_INITIAL_HD_TABLE_SIZE); NGHTTP2_INITIAL_HD_TABLE_SIZE);
if(context->hd_table == NULL) { if(rv != 0) {
return NGHTTP2_ERR_NOMEM; return rv;
} }
memset(context->hd_table, 0, sizeof(nghttp2_hd_entry*)* for(i = 0; static_table[i]; i += 2);
NGHTTP2_INITIAL_HD_TABLE_SIZE); /* TODO handle nomem */
context->hd_table_capacity = NGHTTP2_INITIAL_HD_TABLE_SIZE; context->static_hd_table = malloc(sizeof(nghttp2_hd_entry*)*(i / 2 + 1));
context->hd_tablelen = 0; context->static_hd_table[i / 2] = NULL;
if(role == NGHTTP2_HD_ROLE_INFLATE) { if(role == NGHTTP2_HD_ROLE_INFLATE) {
context->emit_set = malloc(sizeof(nghttp2_hd_entry*)* context->emit_set = malloc(sizeof(nghttp2_hd_entry*)*
NGHTTP2_INITIAL_EMIT_SET_SIZE); NGHTTP2_INITIAL_EMIT_SET_SIZE);
if(context->emit_set == NULL) { if(context->emit_set == NULL) {
free(context->hd_table); nghttp2_hd_ringbuf_free(&context->hd_table);
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
memset(context->emit_set, 0, sizeof(nghttp2_hd_entry*)* memset(context->emit_set, 0, sizeof(nghttp2_hd_entry*)*
@ -196,30 +245,19 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context,
} }
context->emit_setlen = 0; context->emit_setlen = 0;
if(side == NGHTTP2_HD_SIDE_CLIENT) {
ini_table = reqhd_table;
} else {
ini_table = reshd_table;
}
context->hd_table_bufsize = 0; context->hd_table_bufsize = 0;
for(i = 0; ini_table[i]; i += 2) { for(i = 0; static_table[i]; i += 2) {
nghttp2_hd_entry *p = malloc(sizeof(nghttp2_hd_entry)); nghttp2_hd_entry *p = malloc(sizeof(nghttp2_hd_entry));
if(p == NULL) { if(p == NULL) {
for(i = 0; i < context->hd_tablelen; ++i) { nghttp2_hd_ringbuf_free(&context->hd_table);
nghttp2_hd_entry_free(context->hd_table[i]);
free(context->hd_table[i]);
}
free(context->emit_set); free(context->emit_set);
free(context->hd_table);
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
nghttp2_hd_entry_init(p, i / 2, NGHTTP2_HD_FLAG_NONE, nghttp2_hd_entry_init(p, NGHTTP2_HD_FLAG_NONE,
(uint8_t*)ini_table[i], strlen(ini_table[i]), (uint8_t*)static_table[i], strlen(static_table[i]),
(uint8_t*)ini_table[i + 1], (uint8_t*)static_table[i + 1],
strlen(ini_table[i+1])); strlen(static_table[i+1]));
context->hd_table[context->hd_tablelen++] = p; context->static_hd_table[i / 2] = p;
context->hd_table_bufsize += NGHTTP2_HD_ENTRY_OVERHEAD +
p->nv.namelen + p->nv.valuelen;
} }
return 0; return 0;
} }
@ -244,14 +282,9 @@ static void nghttp2_hd_context_free(nghttp2_hd_context *context)
free(ent); free(ent);
} }
} }
for(i = 0; i < context->hd_tablelen; ++i) { nghttp2_hd_ringbuf_free(&context->hd_table);
nghttp2_hd_entry *ent = context->hd_table[i]; free(context->static_hd_table);
--ent->ref;
nghttp2_hd_entry_free(ent);
free(ent);
}
free(context->emit_set); free(context->emit_set);
free(context->hd_table);
} }
void nghttp2_hd_deflate_free(nghttp2_hd_context *deflater) void nghttp2_hd_deflate_free(nghttp2_hd_context *deflater)
@ -478,17 +511,19 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t blocklen = count_encoded_length(index + 1, 5) + size_t blocklen = count_encoded_length(index + 1, 6) +
count_encoded_length(valuelen, 0) + valuelen; count_encoded_length(valuelen, 0) + valuelen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen); rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr; bufp = *buf_ptr + *offset_ptr;
bufp += encode_length(bufp, index + 1, 5); bufp += encode_length(bufp, index + 1, 6);
bufp += encode_length(bufp, valuelen, 0); bufp += encode_length(bufp, valuelen, 0);
memcpy(bufp, value, valuelen); memcpy(bufp, value, valuelen);
(*buf_ptr)[*offset_ptr] |= inc_indexing ? 0x40u : 0x60u; if(!inc_indexing) {
(*buf_ptr)[*offset_ptr] |= 0x40u;
}
assert(bufp+valuelen - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen); assert(bufp+valuelen - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen);
*offset_ptr += blocklen; *offset_ptr += blocklen;
return 0; return 0;
@ -507,7 +542,7 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr; bufp = *buf_ptr + *offset_ptr;
*bufp++ = inc_indexing ? 0x40u : 0x60u; *bufp++ = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, nv->namelen, 0); bufp += encode_length(bufp, nv->namelen, 0);
memcpy(bufp, nv->name, nv->namelen); memcpy(bufp, nv->name, nv->namelen);
bufp += nv->namelen; bufp += nv->namelen;
@ -517,54 +552,6 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
return 0; return 0;
} }
static int emit_subst_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen,
size_t subindex)
{
int rv;
uint8_t *bufp;
size_t blocklen = count_encoded_length(index + 1, 6) +
count_encoded_length(subindex, 0) +
count_encoded_length(valuelen, 0) + valuelen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
bufp += encode_length(bufp, index + 1, 6);
bufp += encode_length(bufp, subindex, 0);
bufp += encode_length(bufp, valuelen, 0);
memcpy(bufp, value, valuelen);
*offset_ptr += blocklen;
return 0;
}
static int emit_subst_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
size_t subindex)
{
int rv;
uint8_t *bufp;
size_t blocklen = 1 + count_encoded_length(nv->namelen, 0) + nv->namelen +
count_encoded_length(subindex, 0) +
count_encoded_length(nv->valuelen, 0) + nv->valuelen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
*bufp++ = 0;
bufp += encode_length(bufp, nv->namelen, 0);
memcpy(bufp, nv->name, nv->namelen);
bufp += nv->namelen;
bufp += encode_length(bufp, subindex, 0);
bufp += encode_length(bufp, nv->valuelen, 0);
memcpy(bufp, nv->value, nv->valuelen);
*offset_ptr += blocklen;
return 0;
}
/* /*
* Emit common header with |index| by toggle off and on (thus 2 * Emit common header with |index| by toggle off and on (thus 2
* indexed representation emissions). * indexed representation emissions).
@ -592,43 +579,35 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
nghttp2_nv *nv) nghttp2_nv *nv)
{ {
int rv; int rv;
size_t i;
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
size_t room = entry_room(nv->namelen, nv->valuelen); size_t room = entry_room(nv->namelen, nv->valuelen);
context->hd_table_bufsize += room; context->hd_table_bufsize += room;
for(i = 0; i < context->hd_tablelen && while(context->hd_table_bufsize > NGHTTP2_HD_MAX_BUFFER_SIZE &&
context->hd_table_bufsize > NGHTTP2_HD_MAX_BUFFER_SIZE; ++i) { context->hd_table.len > 0) {
nghttp2_hd_entry *ent = context->hd_table[i]; size_t index = context->hd_table.len - 1;
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->role == NGHTTP2_HD_ROLE_DEFLATE && if(context->role == NGHTTP2_HD_ROLE_DEFLATE &&
(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT)) { (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
table. If we don't do this, we have to emit it in literal table. If we don't do this, we have to emit it in literal
representation which hurts compression. */ representation which hurts compression. */
rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, ent->index); rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) { if(rv != 0) {
return NULL; return NULL;
} }
} }
ent->index = NGHTTP2_HD_INVALID_INDEX; 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);
} }
} }
if(i > 0) {
size_t j;
for(j = 0; i < context->hd_tablelen; ++i, ++j) {
context->hd_table[j] = context->hd_table[i];
context->hd_table[j]->index = j;
}
context->hd_tablelen = j;
}
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;
} }
rv = nghttp2_hd_entry_init(new_ent, context->hd_tablelen, rv = nghttp2_hd_entry_init(new_ent,
NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_ALLOC |
NGHTTP2_HD_FLAG_VALUE_ALLOC, NGHTTP2_HD_FLAG_VALUE_ALLOC,
nv->name, nv->namelen, nv->value, nv->valuelen); nv->name, nv->namelen, nv->value, nv->valuelen);
@ -639,127 +618,61 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
if(room > NGHTTP2_HD_MAX_BUFFER_SIZE) { if(room > NGHTTP2_HD_MAX_BUFFER_SIZE) {
/* 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. */
new_ent->index = NGHTTP2_HD_INVALID_INDEX;
--new_ent->ref; --new_ent->ref;
} else { } else {
/* Because of current NGHTTP2_HD_MAX_BUFFER_SIZE,
NGHTTP2_HD_ENTRY_OVERHEAD and NGHTTP2_INITIAL_HD_TABLE_SIZE,
context->hd_tablelen is strictly less than
context->hd_table_capacity. */
assert(context->hd_tablelen < context->hd_table_capacity);
context->hd_table[context->hd_tablelen++] = new_ent;
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET; new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent);
} }
return new_ent; return new_ent;
} }
/* static ssize_t find_in_hd_table(nghttp2_hd_context *context, nghttp2_nv *nv)
* This function does not take parameter for header block emission
* because our encoder never use substitution.
*/
static nghttp2_hd_entry* add_hd_table_subst(nghttp2_hd_context *context,
nghttp2_nv *nv, size_t subindex)
{
int rv;
size_t i;
int k;
nghttp2_hd_entry *new_ent;
size_t room = entry_room(nv->namelen, nv->valuelen);
if(context->hd_tablelen <= subindex) {
return NULL;
}
context->hd_table_bufsize -=
entry_room(context->hd_table[subindex]->nv.namelen,
context->hd_table[subindex]->nv.valuelen);
context->hd_table_bufsize += room;
k = subindex;
for(i = 0; i < context->hd_tablelen &&
context->hd_table_bufsize > NGHTTP2_HD_MAX_BUFFER_SIZE; ++i, --k) {
nghttp2_hd_entry *ent = context->hd_table[i];
if(i != subindex) {
context->hd_table_bufsize -= entry_room(ent->nv.namelen,
ent->nv.valuelen);
}
ent->index = NGHTTP2_HD_INVALID_INDEX;
if(--ent->ref == 0) {
nghttp2_hd_entry_free(ent);
free(ent);
}
}
if(i > 0) {
size_t j;
/* k < 0 means that the index to substitute originally was
evicted. Therefore, index 0 is the position to substitute
now. */
if(k < 0) {
j = 1;
} else {
j = 0;
}
for(; i < context->hd_tablelen; ++i, ++j) {
context->hd_table[j] = context->hd_table[i];
context->hd_table[j]->index = j;
}
context->hd_tablelen = j;
}
new_ent = malloc(sizeof(nghttp2_hd_entry));
if(new_ent == NULL) {
return NULL;
}
if(k >= 0) {
nghttp2_hd_entry *ent = context->hd_table[k];
ent->index = NGHTTP2_HD_INVALID_INDEX;
if(--ent->ref == 0) {
nghttp2_hd_entry_free(ent);
free(ent);
}
} else {
k = 0;
}
rv = nghttp2_hd_entry_init(new_ent, k,
NGHTTP2_HD_FLAG_NAME_ALLOC |
NGHTTP2_HD_FLAG_VALUE_ALLOC,
nv->name, nv->namelen, nv->value, nv->valuelen);
if(rv != 0) {
free(new_ent);
return NULL;
}
if(room > NGHTTP2_HD_MAX_BUFFER_SIZE) {
new_ent->index = NGHTTP2_HD_INVALID_INDEX;
--new_ent->ref;
context->hd_tablelen = 0;
} else {
context->hd_table[new_ent->index] = new_ent;
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
}
return new_ent;
}
static nghttp2_hd_entry* find_in_hd_table(nghttp2_hd_context *context,
nghttp2_nv *nv)
{ {
size_t i; size_t i;
for(i = 0; i < context->hd_tablelen; ++i) { for(i = 0; i < context->hd_table.len; ++i) {
nghttp2_hd_entry *ent = context->hd_table[i]; nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i);
if(nghttp2_nv_equal(&ent->nv, nv)) { if(nghttp2_nv_equal(&ent->nv, nv)) {
return ent; return i;
} }
} }
return NULL; for(i = 0; context->static_hd_table[i]; ++i) {
nghttp2_hd_entry *ent = context->static_hd_table[i];
if(nghttp2_nv_equal(&ent->nv, nv)) {
return context->hd_table.len + i;
}
}
return -1;
} }
static nghttp2_hd_entry* find_name_in_hd_table(nghttp2_hd_context *context, static ssize_t find_name_in_hd_table(nghttp2_hd_context *context,
nghttp2_nv *nv) nghttp2_nv *nv)
{ {
size_t i; size_t i;
for(i = 0; i < context->hd_tablelen; ++i) { for(i = 0; i < context->hd_table.len; ++i) {
nghttp2_hd_entry *ent = context->hd_table[i]; nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i);
if(ent->nv.namelen == nv->namelen && if(ent->nv.namelen == nv->namelen &&
memcmp(ent->nv.name, nv->name, nv->namelen) == 0) { memcmp(ent->nv.name, nv->name, nv->namelen) == 0) {
return ent; return i;
} }
} }
return NULL; for(i = 0; context->static_hd_table[i]; ++i) {
nghttp2_hd_entry *ent = context->static_hd_table[i];
if(ent->nv.namelen == nv->namelen &&
memcmp(ent->nv.name, nv->name, nv->namelen) == 0) {
return context->hd_table.len + i;
}
}
return -1;
}
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t index)
{
if(index < context->hd_table.len) {
return nghttp2_hd_ringbuf_get(&context->hd_table, index);
} else {
return context->static_hd_table[index - context->hd_table.len];
}
} }
static int deflate_nv(nghttp2_hd_context *deflater, static int deflate_nv(nghttp2_hd_context *deflater,
@ -769,11 +682,13 @@ static int deflate_nv(nghttp2_hd_context *deflater,
{ {
int rv; int rv;
nghttp2_hd_entry *ent; nghttp2_hd_entry *ent;
ent = find_in_hd_table(deflater, nv); rv = find_in_hd_table(deflater, nv);
if(ent) { if(rv != -1) {
size_t index = rv;
ent = nghttp2_hd_table_get(deflater, index);
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) { 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, ent->index); rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
@ -803,18 +718,18 @@ static int deflate_nv(nghttp2_hd_context *deflater,
ent->flags |= NGHTTP2_HD_FLAG_IMPLICIT_EMIT; ent->flags |= NGHTTP2_HD_FLAG_IMPLICIT_EMIT;
} }
for(; num_emits > 0; --num_emits) { for(; num_emits > 0; --num_emits) {
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, ent->index); rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) { if(rv != 0) {
break; break;
} }
} }
} }
} else { } else {
uint8_t index = NGHTTP2_HD_INVALID_INDEX; ssize_t index = -1;
int incidx = 0; int incidx = 0;
ent = find_name_in_hd_table(deflater, nv); rv = find_name_in_hd_table(deflater, nv);
if(ent) { if(rv != -1) {
index = ent->index; index = rv;
} }
if(entry_room(nv->namelen, nv->valuelen) <= NGHTTP2_HD_MAX_ENTRY_SIZE) { if(entry_room(nv->namelen, nv->valuelen) <= NGHTTP2_HD_MAX_ENTRY_SIZE) {
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
@ -826,7 +741,7 @@ static int deflate_nv(nghttp2_hd_context *deflater,
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
incidx = 1; incidx = 1;
} }
if(index == NGHTTP2_HD_INVALID_INDEX) { 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);
} else { } else {
rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index, rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index,
@ -839,6 +754,28 @@ static int deflate_nv(nghttp2_hd_context *deflater,
return 0; return 0;
} }
static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
size_t index,
uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *offset_ptr)
{
int rv;
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) &&
(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) == 0 &&
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
/* This entry is not present in the current header set and must
be removed. */
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
if(rv != 0) {
return rv;
}
}
ent->flags &= ~(NGHTTP2_HD_FLAG_EMIT | NGHTTP2_HD_FLAG_IMPLICIT_EMIT);
return 0;
}
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr, uint8_t **buf_ptr, size_t *buflen_ptr,
size_t nv_offset, size_t nv_offset,
@ -856,17 +793,20 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
goto fail; goto fail;
} }
} }
for(i = 0; i < deflater->hd_tablelen; ++i) { for(i = 0; i < deflater->hd_table.len; ++i) {
nghttp2_hd_entry *ent = deflater->hd_table[i]; nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->hd_table, i);
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) && rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset);
(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) == 0 && if(rv != 0) {
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) { goto fail;
/* This entry is not present in the current header set and must }
be removed. */ }
ent->flags ^= NGHTTP2_HD_FLAG_REFSET; for(i = 0; deflater->static_hd_table[i]; ++i) {
rv = emit_indexed_block(buf_ptr, buflen_ptr, &offset, ent->index); 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;
} }
ent->flags &= ~(NGHTTP2_HD_FLAG_EMIT | NGHTTP2_HD_FLAG_IMPLICIT_EMIT);
} }
return offset - nv_offset; return offset - nv_offset;
fail: fail:
@ -874,6 +814,28 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
return rv; return rv;
} }
static int inflater_post_process_hd_entry(nghttp2_hd_context *inflater,
nghttp2_hd_entry *ent,
nghttp2_nva_out *nva_out_ptr)
{
int rv;
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) &&
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
rv = emit_indexed_header(inflater, nva_out_ptr, ent);
if(rv != 0) {
return rv;
}
}
ent->flags &= ~NGHTTP2_HD_FLAG_EMIT;
return 0;
}
static int check_index_range(nghttp2_hd_context *context, size_t index)
{
return index < context->hd_table.len +
sizeof(static_table)/sizeof(static_table[0])/2;
}
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater, ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
nghttp2_nv **nva_ptr, nghttp2_nv **nva_ptr,
uint8_t *in, size_t inlen) uint8_t *in, size_t inlen)
@ -898,11 +860,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
} }
if(inflater->hd_tablelen <= index) { if(!check_index_range(inflater, index)) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
} }
ent = inflater->hd_table[index]; ent = nghttp2_hd_table_get(inflater, index);
ent->flags ^= NGHTTP2_HD_FLAG_REFSET; ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) { if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
rv = emit_indexed_header(inflater, &nva_out, ent); rv = emit_indexed_header(inflater, &nva_out, ent);
@ -910,10 +872,10 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
} }
} else if(c == 0x40u || c == 0x60u || c == 0) { } else if(c == 0x40u || c == 0) {
/* Literal Header Repr - New Name */ /* Literal Header Repr - New Name */
nghttp2_nv nv; nghttp2_nv nv;
ssize_t namelen, valuelen, subindex; ssize_t namelen, valuelen;
if(++in == last) { if(++in == last) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
@ -929,13 +891,6 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
} }
nv.name = in; nv.name = in;
in += namelen; in += namelen;
if(c == 0) {
in = decode_length(&subindex, in, last, 0);
if(subindex < 0) {
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
}
in = decode_length(&valuelen, in, last, 0); in = decode_length(&valuelen, in, last, 0);
if(valuelen < 0 || in + valuelen > last) { if(valuelen < 0 || in + valuelen > last) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
@ -946,15 +901,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
nv.valuelen = valuelen; nv.valuelen = valuelen;
in += valuelen; in += valuelen;
nghttp2_downcase(nv.name, nv.namelen); nghttp2_downcase(nv.name, nv.namelen);
if(c == 0x60u) { if(c == 0x40u) {
rv = emit_newname_header(inflater, &nva_out, &nv); rv = emit_newname_header(inflater, &nva_out, &nv);
} else { } else {
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
if(c == 0) { new_ent = add_hd_table_incremental(inflater, NULL, NULL, NULL, &nv);
new_ent = add_hd_table_subst(inflater, &nv, subindex);
} else {
new_ent = add_hd_table_incremental(inflater, NULL, NULL, NULL, &nv);
}
if(new_ent) { if(new_ent) {
rv = emit_indexed_header(inflater, &nva_out, new_ent); rv = emit_indexed_header(inflater, &nva_out, new_ent);
} else { } else {
@ -968,25 +919,18 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
/* Literal Header Repr - Indexed Name */ /* Literal Header Repr - Indexed Name */
nghttp2_hd_entry *ent; nghttp2_hd_entry *ent;
uint8_t *value; uint8_t *value;
ssize_t valuelen, index, subindex; ssize_t valuelen, index;
in = decode_length(&index, in, last, (c & 0x40u) ? 5 : 6); in = decode_length(&index, in, last, 6);
if(index < 0) { if(index < 0) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
} }
--index; --index;
if(inflater->hd_tablelen <= index) { if(!check_index_range(inflater, index)) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail; goto fail;
} }
ent = inflater->hd_table[index]; ent = nghttp2_hd_table_get(inflater, index);
if((c & 0x40u) == 0) {
in = decode_length(&subindex, in, last, 0);
if(subindex < 0) {
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
}
in = decode_length(&valuelen, in , last, 0); in = decode_length(&valuelen, in , last, 0);
if(valuelen < 0 || in + valuelen > last) { if(valuelen < 0 || in + valuelen > last) {
rv = NGHTTP2_ERR_HEADER_COMP; rv = NGHTTP2_ERR_HEADER_COMP;
@ -994,7 +938,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
} }
value = in; value = in;
in += valuelen; in += valuelen;
if((c & 0x60u) == 0x60u) { if((c & 0x40u) == 0x40u) {
rv = emit_indname_header(inflater, &nva_out, ent, value, valuelen); rv = emit_indname_header(inflater, &nva_out, ent, value, valuelen);
} else { } else {
nghttp2_nv nv; nghttp2_nv nv;
@ -1004,11 +948,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
nv.namelen = ent->nv.namelen; nv.namelen = ent->nv.namelen;
nv.value = value; nv.value = value;
nv.valuelen = valuelen; nv.valuelen = valuelen;
if((c & 0x40u) == 0) { new_ent = add_hd_table_incremental(inflater, NULL, NULL, NULL, &nv);
new_ent = add_hd_table_subst(inflater, &nv, subindex);
} else {
new_ent = add_hd_table_incremental(inflater, NULL, NULL, NULL, &nv);
}
if(--ent->ref == 0) { if(--ent->ref == 0) {
nghttp2_hd_entry_free(ent); nghttp2_hd_entry_free(ent);
free(ent); free(ent);
@ -1024,16 +964,19 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
} }
} }
} }
for(i = 0; i < inflater->hd_tablelen; ++i) { for(i = 0; i < inflater->hd_table.len; ++i) {
nghttp2_hd_entry *ent = inflater->hd_table[i]; nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&inflater->hd_table, i);
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) && rv = inflater_post_process_hd_entry(inflater, ent, &nva_out);
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) { if(rv != 0) {
rv = emit_indexed_header(inflater, &nva_out, ent); goto fail;
if(rv != 0) { }
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;
} }
ent->flags &= ~NGHTTP2_HD_FLAG_EMIT;
} }
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;
@ -1073,20 +1016,3 @@ int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
{ {
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);
} }
int nghttp2_hd_emit_subst_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen,
size_t subindex)
{
return emit_subst_indname_block(buf_ptr, buflen_ptr, offset_ptr, index,
value, valuelen, subindex);
}
int nghttp2_hd_emit_subst_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
size_t subindex)
{
return emit_subst_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv,
subindex);
}

View File

@ -70,21 +70,23 @@ typedef struct {
nghttp2_nv nv; nghttp2_nv nv;
/* Reference count */ /* Reference count */
uint8_t ref; uint8_t ref;
/* Index in the header table */
uint8_t index;
uint8_t flags; uint8_t flags;
} nghttp2_hd_entry; } nghttp2_hd_entry;
typedef struct {
nghttp2_hd_entry **buffer;
size_t mask;
size_t first;
size_t len;
} nghttp2_hd_ringbuf;
typedef struct { typedef struct {
/* Header table */ /* Header table */
nghttp2_hd_entry **hd_table; nghttp2_hd_ringbuf hd_table;
nghttp2_hd_entry **static_hd_table;
/* Holding emitted entry in deflating header block to retain /* Holding emitted entry in deflating header block to retain
reference count. */ reference count. */
nghttp2_hd_entry **emit_set; nghttp2_hd_entry **emit_set;
/* The capacity of the |hd_table| */
uint16_t hd_table_capacity;
/* The number of entry the |hd_table| contains */
uint16_t hd_tablelen;
/* The capacity of the |emit_set| */ /* The capacity of the |emit_set| */
uint16_t emit_set_capacity; uint16_t emit_set_capacity;
/* The number of entry the |emit_set| contains */ /* The number of entry the |emit_set| contains */
@ -114,7 +116,7 @@ typedef struct {
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t index, uint8_t flags, int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags,
uint8_t *name, uint16_t namelen, uint8_t *name, uint16_t namelen,
uint8_t *value, uint16_t valuelen); uint8_t *value, uint16_t valuelen);
@ -238,4 +240,8 @@ int nghttp2_hd_emit_subst_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv, size_t *offset_ptr, nghttp2_nv *nv,
size_t subindex); size_t subindex);
/* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t index);
#endif /* NGHTTP2_HD_COMP_H */ #endif /* NGHTTP2_HD_COMP_H */

View File

@ -237,16 +237,6 @@ int main(int argc, char* argv[])
test_nghttp2_hd_inflate_indname_inc_eviction) || test_nghttp2_hd_inflate_indname_inc_eviction) ||
!CU_add_test(pSuite, "hd_inflate_newname_inc", !CU_add_test(pSuite, "hd_inflate_newname_inc",
test_nghttp2_hd_inflate_newname_inc) || test_nghttp2_hd_inflate_newname_inc) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst",
test_nghttp2_hd_inflate_indname_subst) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction",
test_nghttp2_hd_inflate_indname_subst_eviction) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction_neg",
test_nghttp2_hd_inflate_indname_subst_eviction_neg) ||
!CU_add_test(pSuite, "hd_inflate_newname_subst",
test_nghttp2_hd_inflate_newname_subst) ||
!CU_add_test(pSuite, "hd_inflate_clearall_subst",
test_nghttp2_hd_inflate_clearall_subst) ||
!CU_add_test(pSuite, "hd_inflate_clearall_inc", !CU_add_test(pSuite, "hd_inflate_clearall_inc",
test_nghttp2_hd_inflate_clearall_inc) || test_nghttp2_hd_inflate_clearall_inc) ||
!CU_add_test(pSuite, "hd_deflate_inflate", !CU_add_test(pSuite, "hd_deflate_inflate",

View File

@ -33,6 +33,8 @@
#include "nghttp2_frame.h" #include "nghttp2_frame.h"
#include "nghttp2_test_helper.h" #include "nghttp2_test_helper.h"
#define GET_TABLE_ENT(context, index) nghttp2_hd_table_get(context, index)
static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len) static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len)
{ {
size_t i; size_t i;
@ -65,15 +67,12 @@ void test_nghttp2_hd_deflate(void)
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_CLIENT)); CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_CLIENT));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER));
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);
nghttp2_hd_end_headers(&deflater); nghttp2_hd_end_headers(&deflater);
CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset, CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset,
blocklen)); blocklen));
assert_nv_equal(nva1, resnva, 3); assert_nv_equal(nva1, resnva, 3);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
@ -99,10 +98,8 @@ void test_nghttp2_hd_deflate(void)
sizeof(nva3)/sizeof(nghttp2_nv)); sizeof(nva3)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
nghttp2_hd_end_headers(&deflater); nghttp2_hd_end_headers(&deflater);
CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset, CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset,
blocklen)); blocklen));
assert_nv_equal(nva3, resnva, 3); assert_nv_equal(nva3, resnva, 3);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
@ -216,8 +213,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
/* Put :scheme: http (index = 0) in reference set */ /* Put :scheme: http (index = 0) in reference set */
deflater.hd_table[0]->flags |= NGHTTP2_HD_FLAG_REFSET; GET_TABLE_ENT(&deflater, 0)->flags |= NGHTTP2_HD_FLAG_REFSET;
inflater.hd_table[0]->flags |= NGHTTP2_HD_FLAG_REFSET; GET_TABLE_ENT(&inflater, 0)->flags |= NGHTTP2_HD_FLAG_REFSET;
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva,
sizeof(nva)/sizeof(nghttp2_nv)); sizeof(nva)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
@ -252,8 +249,9 @@ void test_nghttp2_hd_inflate_indname_inc(void)
nv.value, nv.valuelen, 1)); nv.value, nv.valuelen, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1); assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(31 == inflater.hd_tablelen); CU_ASSERT(1 == inflater.hd_table.len);
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1); assert_nv_equal(&nv,
&GET_TABLE_ENT(&inflater, inflater.hd_table.len-1)->nv, 1);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
free(buf); free(buf);
@ -266,17 +264,21 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
uint8_t *buf = NULL; uint8_t *buf = NULL;
size_t buflen = 0; size_t buflen = 0;
size_t offset = 0; size_t offset = 0;
/* Default header table capacity is 1262. Adding 2835 bytes, uint8_t value[1024];
including overhead, to the table evicts first entry.
use name ":host" which index 2 and value length 2798. */
uint8_t value[2798];
nghttp2_nv *resnva; nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
memset(value, '0', sizeof(value)); memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 2, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 2,
value, sizeof(value), 1)); value, sizeof(value), 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 3,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 4,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 5,
value, sizeof(value), 1));
CU_ASSERT(4 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen); CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen)); CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen); CU_ASSERT(sizeof(value) == resnva[0].valuelen);
@ -284,8 +286,8 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater); nghttp2_hd_end_headers(&inflater);
CU_ASSERT(30 == inflater.hd_tablelen); CU_ASSERT(3 == inflater.hd_table.len);
CU_ASSERT(inflater.hd_table[29]->flags & NGHTTP2_HD_FLAG_REFSET); CU_ASSERT(GET_TABLE_ENT(&inflater, 0)->flags & NGHTTP2_HD_FLAG_REFSET);
free(buf); free(buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
@ -305,118 +307,9 @@ void test_nghttp2_hd_inflate_newname_inc(void)
&nv, 1)); &nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1); assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(31 == inflater.hd_tablelen); CU_ASSERT(1 == inflater.hd_table.len);
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1); assert_nv_equal(&nv,
&GET_TABLE_ENT(&inflater, inflater.hd_table.len-1)->nv, 1);
nghttp2_nv_array_del(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
11,
nv.value, nv.valuelen,
11));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(30 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[11]->nv, 1);
nghttp2_nv_array_del(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst_eviction(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
/* Default header table capacity is 1262. Adding 2877 bytes,
including overhead, to the table evicts first entry.
use name ":host" which index 2 and value length 2840. */
uint8_t value[2840];
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
2,
value, sizeof(value), 2));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen);
nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(29 == inflater.hd_tablelen);
CU_ASSERT(inflater.hd_table[1]->flags & NGHTTP2_HD_FLAG_REFSET);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst_eviction_neg(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
/* Default header table capacity is 1262. Adding 2878 bytes,
including overhead, to the table evicts first 2 entries.
use name ":host" which index 2 and value length 2841. */
uint8_t value[2841];
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
memset(value, '0', sizeof(value));
/* Try to substitute index 0, but it will be evicted */
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
2,
value, sizeof(value), 0));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen);
nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(29 == inflater.hd_tablelen);
CU_ASSERT(inflater.hd_table[0]->flags & NGHTTP2_HD_FLAG_REFSET);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_subst(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_newname_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(30 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[1]->nv, 1);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
free(buf); free(buf);
@ -446,7 +339,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
&nv, 1)); &nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1); assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(0 == inflater.hd_tablelen); CU_ASSERT(0 == inflater.hd_table.len);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater); nghttp2_hd_end_headers(&inflater);
@ -454,7 +347,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
/* Do it again */ /* Do it again */
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1); assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(0 == inflater.hd_tablelen); CU_ASSERT(0 == inflater.hd_table.len);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
nghttp2_hd_end_headers(&inflater); nghttp2_hd_end_headers(&inflater);
@ -468,38 +361,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
&nv, 1)); &nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset)); CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1); assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(1 == inflater.hd_tablelen); CU_ASSERT(1 == inflater.hd_table.len);
nghttp2_nv_array_del(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_clearall_subst(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv;
nghttp2_nv *resnva;
uint8_t value[4060];
/* Total 4097 bytes space required to hold this entry */
nv.name = (uint8_t*)"alpha";
nv.namelen = strlen((char*)nv.name);
memset(value, '0', sizeof(value));
nv.value = value;
nv.valuelen = sizeof(value);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_newname_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(0 == inflater.hd_tablelen);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);

View File

@ -31,12 +31,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void);
void test_nghttp2_hd_inflate_indname_inc(void); void test_nghttp2_hd_inflate_indname_inc(void);
void test_nghttp2_hd_inflate_indname_inc_eviction(void); void test_nghttp2_hd_inflate_indname_inc_eviction(void);
void test_nghttp2_hd_inflate_newname_inc(void); void test_nghttp2_hd_inflate_newname_inc(void);
void test_nghttp2_hd_inflate_indname_subst(void);
void test_nghttp2_hd_inflate_indname_subst_eviction(void);
void test_nghttp2_hd_inflate_indname_subst_eviction_neg(void);
void test_nghttp2_hd_inflate_newname_subst(void);
void test_nghttp2_hd_inflate_clearall_inc(void); void test_nghttp2_hd_inflate_clearall_inc(void);
void test_nghttp2_hd_inflate_clearall_subst(void);
void test_nghttp2_hd_deflate_inflate(void); void test_nghttp2_hd_deflate_inflate(void);
#endif /* NGHTTP2_HD_TEST_H */ #endif /* NGHTTP2_HD_TEST_H */