Implement draft-ietf-httpbis-header-compression-02
This commit is contained in:
parent
0b005e3f22
commit
346fafde3f
|
@ -34,9 +34,9 @@
|
||||||
#include "nghttp2_buffer.h"
|
#include "nghttp2_buffer.h"
|
||||||
|
|
||||||
/* The maximum payload length of a frame */
|
/* The maximum payload length of a frame */
|
||||||
/* TODO The spec says the max payload length in HTTP is ((1 << 14) -
|
|
||||||
1) */
|
|
||||||
#define NGHTTP2_MAX_FRAME_LENGTH ((1 << 16) - 1)
|
#define NGHTTP2_MAX_FRAME_LENGTH ((1 << 16) - 1)
|
||||||
|
/* The maximum paylaod length of a frame used in HTTP */
|
||||||
|
#define NGHTTP2_MAX_HTTP_FRAME_LENGTH ((1 << 14) - 1)
|
||||||
|
|
||||||
/* The maximum header block length. This is not specified by the
|
/* The maximum header block length. This is not specified by the
|
||||||
spec. We just chose the arbitrary size */
|
spec. We just chose the arbitrary size */
|
||||||
|
|
532
lib/nghttp2_hd.c
532
lib/nghttp2_hd.c
|
@ -43,17 +43,13 @@ static const char *reqhd_table[] = {
|
||||||
"accept-language", "",
|
"accept-language", "",
|
||||||
"cookie", "",
|
"cookie", "",
|
||||||
"if-modified-since", "",
|
"if-modified-since", "",
|
||||||
"keep-alive", "",
|
|
||||||
"user-agent", "",
|
"user-agent", "",
|
||||||
"proxy-connection", "",
|
|
||||||
"referer", "",
|
"referer", "",
|
||||||
"accept-datetime", "",
|
|
||||||
"authorization", "",
|
"authorization", "",
|
||||||
"allow", "",
|
"allow", "",
|
||||||
"cache-control", "",
|
"cache-control", "",
|
||||||
"connection", "",
|
"connection", "",
|
||||||
"content-length", "",
|
"content-length", "",
|
||||||
"content-md5", "",
|
|
||||||
"content-type", "",
|
"content-type", "",
|
||||||
"date", "",
|
"date", "",
|
||||||
"expect", "",
|
"expect", "",
|
||||||
|
@ -63,13 +59,9 @@ static const char *reqhd_table[] = {
|
||||||
"if-range", "",
|
"if-range", "",
|
||||||
"if-unmodified-since", "",
|
"if-unmodified-since", "",
|
||||||
"max-forwards", "",
|
"max-forwards", "",
|
||||||
"pragma", "",
|
|
||||||
"proxy-authorization", "",
|
"proxy-authorization", "",
|
||||||
"range", "",
|
"range", "",
|
||||||
"te", "",
|
|
||||||
"upgrade", "",
|
|
||||||
"via", "",
|
"via", "",
|
||||||
"warning", "",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,19 +87,14 @@ static const char *reshd_table[] = {
|
||||||
"content-encoding", "",
|
"content-encoding", "",
|
||||||
"content-language", "",
|
"content-language", "",
|
||||||
"content-location", "",
|
"content-location", "",
|
||||||
"content-md5", "",
|
|
||||||
"content-range", "",
|
"content-range", "",
|
||||||
"link", "",
|
"link", "",
|
||||||
"location", "",
|
"location", "",
|
||||||
"p3p", "",
|
|
||||||
"pragma", "",
|
|
||||||
"proxy-authenticate", "",
|
"proxy-authenticate", "",
|
||||||
"refresh", "",
|
"refresh", "",
|
||||||
"retry-after", "",
|
"retry-after", "",
|
||||||
"strict-transport-security", "",
|
"strict-transport-security", "",
|
||||||
"trailer", "",
|
|
||||||
"transfer-encoding", "",
|
"transfer-encoding", "",
|
||||||
"warning", "",
|
|
||||||
"www-authenticate", "",
|
"www-authenticate", "",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -178,19 +165,17 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context,
|
||||||
context->bad = 0;
|
context->bad = 0;
|
||||||
context->hd_table = malloc(sizeof(nghttp2_hd_entry*)*
|
context->hd_table = malloc(sizeof(nghttp2_hd_entry*)*
|
||||||
NGHTTP2_INITIAL_HD_TABLE_SIZE);
|
NGHTTP2_INITIAL_HD_TABLE_SIZE);
|
||||||
|
if(context->hd_table == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
memset(context->hd_table, 0, sizeof(nghttp2_hd_entry*)*
|
memset(context->hd_table, 0, sizeof(nghttp2_hd_entry*)*
|
||||||
NGHTTP2_INITIAL_HD_TABLE_SIZE);
|
NGHTTP2_INITIAL_HD_TABLE_SIZE);
|
||||||
context->hd_table_capacity = NGHTTP2_INITIAL_HD_TABLE_SIZE;
|
context->hd_table_capacity = NGHTTP2_INITIAL_HD_TABLE_SIZE;
|
||||||
context->hd_tablelen = 0;
|
context->hd_tablelen = 0;
|
||||||
|
|
||||||
context->refset = malloc(sizeof(nghttp2_hd_entry*)*
|
context->emit_set = NULL;
|
||||||
NGHTTP2_INITIAL_REFSET_SIZE);
|
context->emit_set_capacity = 0;
|
||||||
context->refset_capacity = NGHTTP2_INITIAL_REFSET_SIZE;
|
context->emit_setlen = 0;
|
||||||
context->refsetlen = 0;
|
|
||||||
|
|
||||||
context->ws = malloc(sizeof(nghttp2_hd_ws_entry)*NGHTTP2_INITIAL_WS_SIZE);
|
|
||||||
context->ws_capacity = NGHTTP2_INITIAL_WS_SIZE;
|
|
||||||
context->wslen = 0;
|
|
||||||
|
|
||||||
if(side == NGHTTP2_HD_SIDE_CLIENT) {
|
if(side == NGHTTP2_HD_SIDE_CLIENT) {
|
||||||
ini_table = reqhd_table;
|
ini_table = reqhd_table;
|
||||||
|
@ -200,6 +185,14 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context,
|
||||||
context->hd_table_bufsize = 0;
|
context->hd_table_bufsize = 0;
|
||||||
for(i = 0; ini_table[i]; i += 2) {
|
for(i = 0; ini_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) {
|
||||||
|
for(i = 0; i < context->hd_tablelen; ++i) {
|
||||||
|
nghttp2_hd_entry_free(context->hd_table[i]);
|
||||||
|
free(context->hd_table[i]);
|
||||||
|
}
|
||||||
|
free(context->hd_table);
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
nghttp2_hd_entry_init(p, i / 2, NGHTTP2_HD_FLAG_NONE,
|
nghttp2_hd_entry_init(p, i / 2, NGHTTP2_HD_FLAG_NONE,
|
||||||
(uint8_t*)ini_table[i], strlen(ini_table[i]),
|
(uint8_t*)ini_table[i], strlen(ini_table[i]),
|
||||||
(uint8_t*)ini_table[i + 1],
|
(uint8_t*)ini_table[i + 1],
|
||||||
|
@ -216,35 +209,11 @@ int nghttp2_hd_deflate_init(nghttp2_hd_context *deflater, nghttp2_hd_side side)
|
||||||
return nghttp2_hd_context_init(deflater, side);
|
return nghttp2_hd_context_init(deflater, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_hd_inflate_init(nghttp2_hd_context *inflater, nghttp2_hd_side side)
|
|
||||||
{
|
|
||||||
return nghttp2_hd_context_init(inflater, side^1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nghttp2_hd_context_free(nghttp2_hd_context *context)
|
static void nghttp2_hd_context_free(nghttp2_hd_context *context)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i = 0; i < context->wslen; ++i) {
|
for(i = 0; i < context->emit_setlen; ++i) {
|
||||||
nghttp2_hd_ws_entry *ent = &context->ws[i];
|
nghttp2_hd_entry *ent = context->emit_set[i];
|
||||||
switch(ent->cat) {
|
|
||||||
case NGHTTP2_HD_CAT_INDEXED:
|
|
||||||
if(--ent->indexed.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ent->indexed.entry);
|
|
||||||
free(ent->indexed.entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_INDNAME:
|
|
||||||
if(--ent->indname.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ent->indname.entry);
|
|
||||||
free(ent->indname.entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(i = 0; i < context->refsetlen; ++i) {
|
|
||||||
nghttp2_hd_entry *ent = context->refset[i];
|
|
||||||
if(--ent->ref == 0) {
|
if(--ent->ref == 0) {
|
||||||
nghttp2_hd_entry_free(ent);
|
nghttp2_hd_entry_free(ent);
|
||||||
free(ent);
|
free(ent);
|
||||||
|
@ -256,11 +225,30 @@ static void nghttp2_hd_context_free(nghttp2_hd_context *context)
|
||||||
nghttp2_hd_entry_free(ent);
|
nghttp2_hd_entry_free(ent);
|
||||||
free(ent);
|
free(ent);
|
||||||
}
|
}
|
||||||
free(context->ws);
|
free(context->emit_set);
|
||||||
free(context->refset);
|
|
||||||
free(context->hd_table);
|
free(context->hd_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_hd_inflate_init(nghttp2_hd_context *inflater, nghttp2_hd_side side)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
rv = nghttp2_hd_context_init(inflater, side^1);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
inflater->emit_set = malloc(sizeof(nghttp2_hd_entry*)*
|
||||||
|
NGHTTP2_INITIAL_EMIT_SET_SIZE);
|
||||||
|
if(inflater->emit_set == NULL) {
|
||||||
|
nghttp2_hd_context_free(inflater);
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memset(inflater->emit_set, 0, sizeof(nghttp2_hd_entry*)*
|
||||||
|
NGHTTP2_INITIAL_EMIT_SET_SIZE);
|
||||||
|
inflater->emit_set_capacity = NGHTTP2_INITIAL_EMIT_SET_SIZE;
|
||||||
|
inflater->emit_setlen = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void nghttp2_hd_deflate_free(nghttp2_hd_context *deflater)
|
void nghttp2_hd_deflate_free(nghttp2_hd_context *deflater)
|
||||||
{
|
{
|
||||||
nghttp2_hd_context_free(deflater);
|
nghttp2_hd_context_free(deflater);
|
||||||
|
@ -318,6 +306,7 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
context->hd_table[context->hd_tablelen++] = new_ent;
|
context->hd_table[context->hd_tablelen++] = new_ent;
|
||||||
|
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
|
||||||
return new_ent;
|
return new_ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,119 +375,84 @@ static nghttp2_hd_entry* add_hd_table_subst(nghttp2_hd_context *context,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
context->hd_table[new_ent->index] = new_ent;
|
context->hd_table[new_ent->index] = new_ent;
|
||||||
|
new_ent->flags |= NGHTTP2_HD_FLAG_REFSET;
|
||||||
return new_ent;
|
return new_ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_workingset(nghttp2_hd_context *context, nghttp2_hd_entry *ent)
|
static int add_nva(nghttp2_nv **nva_ptr, size_t *nvacap_ptr,
|
||||||
|
ssize_t *nvlen_ptr,
|
||||||
|
uint8_t *name, uint16_t namelen,
|
||||||
|
uint8_t *value, uint16_t valuelen)
|
||||||
{
|
{
|
||||||
nghttp2_hd_ws_entry *ws_ent;
|
nghttp2_nv *nv;
|
||||||
if(context->wslen == context->ws_capacity) {
|
if((ssize_t)*nvacap_ptr == *nvlen_ptr) {
|
||||||
|
size_t newcap = *nvacap_ptr == 0 ? 16 : *nvacap_ptr * 2;
|
||||||
|
nghttp2_nv *new_nva = realloc(*nva_ptr, sizeof(nghttp2_nv)*newcap);
|
||||||
|
if(new_nva == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
*nva_ptr = new_nva;
|
||||||
|
*nvacap_ptr = newcap;
|
||||||
|
}
|
||||||
|
nv = &(*nva_ptr)[(*nvlen_ptr)++];
|
||||||
|
nv->name = name;
|
||||||
|
nv->namelen = namelen;
|
||||||
|
nv->value = value;
|
||||||
|
nv->valuelen = valuelen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_emit_set(nghttp2_hd_context *context, nghttp2_hd_entry *ent)
|
||||||
|
{
|
||||||
|
if(context->emit_setlen == context->emit_set_capacity) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
ws_ent = &context->ws[context->wslen++];
|
context->emit_set[context->emit_setlen++] = ent;
|
||||||
ws_ent->cat = NGHTTP2_HD_CAT_INDEXED;
|
|
||||||
ws_ent->indexed.entry = ent;
|
|
||||||
ws_ent->indexed.index = ent->index;
|
|
||||||
++ent->ref;
|
++ent->ref;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_workingset_newname(nghttp2_hd_context *context,
|
static int emit_indexed_header(nghttp2_hd_context *context,
|
||||||
nghttp2_nv *nv)
|
nghttp2_nv **nva_ptr,
|
||||||
|
size_t *nvacap_ptr,
|
||||||
|
ssize_t *nvlen_ptr,
|
||||||
|
nghttp2_hd_entry *ent)
|
||||||
{
|
{
|
||||||
nghttp2_hd_ws_entry *ws_ent;
|
int rv;
|
||||||
if(context->wslen == context->ws_capacity) {
|
rv = add_emit_set(context, ent);
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
ws_ent = &context->ws[context->wslen++];
|
ent->flags |= NGHTTP2_HD_FLAG_EMIT;
|
||||||
ws_ent->cat = NGHTTP2_HD_CAT_NEWNAME;
|
return add_nva(nva_ptr, nvacap_ptr, nvlen_ptr,
|
||||||
ws_ent->newname.nv = *nv;
|
ent->nv.name, ent->nv.namelen,
|
||||||
return 0;
|
ent->nv.value, ent->nv.valuelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_workingset_indname(nghttp2_hd_context *context,
|
static int emit_newname_header(nghttp2_hd_context *context,
|
||||||
nghttp2_hd_entry *ent,
|
nghttp2_nv **nva_ptr,
|
||||||
uint8_t *value, size_t valuelen)
|
size_t *nvacap_ptr,
|
||||||
|
ssize_t *nvlen_ptr,
|
||||||
|
nghttp2_nv *nv)
|
||||||
{
|
{
|
||||||
nghttp2_hd_ws_entry *ws_ent;
|
return add_nva(nva_ptr, nvacap_ptr, nvlen_ptr,
|
||||||
if(context->wslen == context->ws_capacity) {
|
nv->name, nv->namelen, nv->value, nv->valuelen);
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
|
||||||
}
|
|
||||||
ws_ent = &context->ws[context->wslen++];
|
|
||||||
ws_ent->cat = NGHTTP2_HD_CAT_INDNAME;
|
|
||||||
ws_ent->indname.entry = ent;
|
|
||||||
++ent->ref;
|
|
||||||
ws_ent->indname.value = value;
|
|
||||||
ws_ent->indname.valuelen = valuelen;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static nghttp2_hd_ws_entry* find_in_workingset(nghttp2_hd_context *context,
|
static int emit_indname_header(nghttp2_hd_context *context,
|
||||||
nghttp2_nv *nv)
|
nghttp2_nv **nva_ptr,
|
||||||
|
size_t *nvacap_ptr,
|
||||||
|
ssize_t *nvlen_ptr,
|
||||||
|
nghttp2_hd_entry *ent,
|
||||||
|
uint8_t *value, size_t valuelen)
|
||||||
{
|
{
|
||||||
size_t i;
|
int rv;
|
||||||
for(i = 0; i < context->wslen; ++i) {
|
rv = add_emit_set(context, ent);
|
||||||
nghttp2_hd_ws_entry *ent = &context->ws[i];
|
if(rv != 0) {
|
||||||
switch(ent->cat) {
|
return rv;
|
||||||
case NGHTTP2_HD_CAT_INDEXED:
|
|
||||||
if(nghttp2_nv_equal(&ent->indexed.entry->nv, nv)) {
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_INDNAME:
|
|
||||||
if(ent->indname.entry->nv.namelen == nv->namelen &&
|
|
||||||
ent->indname.valuelen == nv->valuelen &&
|
|
||||||
memcmp(ent->indname.entry->nv.name, nv->name, nv->namelen) == 0 &&
|
|
||||||
memcmp(ent->indname.value, nv->value, nv->valuelen) == 0) {
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_NEWNAME:
|
|
||||||
if(nghttp2_nv_equal(&ent->newname.nv, nv)) {
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return add_nva(nva_ptr, nvacap_ptr, nvlen_ptr,
|
||||||
}
|
ent->nv.name, ent->nv.namelen, value, valuelen);
|
||||||
|
|
||||||
static nghttp2_hd_ws_entry* find_in_workingset_by_index
|
|
||||||
(nghttp2_hd_context *context, size_t index)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for(i = 0; i < context->wslen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ent = &context->ws[i];
|
|
||||||
/* Compare against *frozen* index, not the current header table
|
|
||||||
index. */
|
|
||||||
if(ent->cat == NGHTTP2_HD_CAT_INDEXED && ent->indexed.index == index) {
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t remove_from_workingset_by_index
|
|
||||||
(nghttp2_hd_context *context, size_t index)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
size_t res = 0;
|
|
||||||
for(i = 0; i < context->wslen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ws_ent = &context->ws[i];
|
|
||||||
/* Compare against *frozen* index, not the current header table
|
|
||||||
index. */
|
|
||||||
if(ws_ent->cat == NGHTTP2_HD_CAT_INDEXED &&
|
|
||||||
ws_ent->indexed.index == index) {
|
|
||||||
++res;
|
|
||||||
if(--ws_ent->indexed.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ws_ent->indexed.entry);
|
|
||||||
free(ws_ent->indexed.entry);
|
|
||||||
}
|
|
||||||
ws_ent->cat = NGHTTP2_HD_CAT_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static nghttp2_hd_entry* find_in_hd_table(nghttp2_hd_context *context,
|
static nghttp2_hd_entry* find_in_hd_table(nghttp2_hd_context *context,
|
||||||
|
@ -532,7 +486,9 @@ static int ensure_write_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
size_t offset, size_t need)
|
size_t offset, size_t need)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
if(need + offset > NGHTTP2_MAX_FRAME_LENGTH) {
|
/* TODO Remove this limitation when header continuation is
|
||||||
|
implemented. */
|
||||||
|
if(need + offset > NGHTTP2_MAX_HTTP_FRAME_LENGTH) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
|
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
|
||||||
|
@ -742,132 +698,72 @@ static int emit_subst_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_workingset(nghttp2_hd_context *context)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < context->refsetlen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ent = &context->ws[i];
|
|
||||||
ent->cat = NGHTTP2_HD_CAT_INDEXED;
|
|
||||||
ent->indexed.entry = context->refset[i];
|
|
||||||
ent->indexed.index = ent->indexed.entry->index;
|
|
||||||
context->refset[i] = NULL;
|
|
||||||
}
|
|
||||||
context->wslen = context->refsetlen;
|
|
||||||
context->refsetlen = 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,
|
||||||
nghttp2_nv *nv, size_t nvlen)
|
nghttp2_nv *nv, size_t nvlen)
|
||||||
{
|
{
|
||||||
size_t i, j, offset;
|
size_t i, offset;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
if(deflater->bad) {
|
if(deflater->bad) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
create_workingset(deflater);
|
|
||||||
offset = nv_offset;
|
offset = nv_offset;
|
||||||
/* Looks like we need to toggle first, because the index might be
|
|
||||||
overlapped by eviction */
|
|
||||||
for(i = 0; i < deflater->wslen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ws_ent = &deflater->ws[i];
|
|
||||||
int found = 0;
|
|
||||||
assert(ws_ent->cat == NGHTTP2_HD_CAT_INDEXED);
|
|
||||||
for(j = 0; j < nvlen; ++j) {
|
|
||||||
if(nghttp2_nv_equal(&ws_ent->indexed.entry->nv, &nv[j])) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found) {
|
|
||||||
rv = emit_indexed_block(buf_ptr, buflen_ptr, &offset,
|
|
||||||
ws_ent->indexed.index);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if(--ws_ent->indexed.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ws_ent->indexed.entry);
|
|
||||||
free(ws_ent->indexed.entry);
|
|
||||||
}
|
|
||||||
ws_ent->cat = NGHTTP2_HD_CAT_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(i = 0; i < nvlen; ++i) {
|
for(i = 0; i < nvlen; ++i) {
|
||||||
if(!find_in_workingset(deflater, &nv[i])) {
|
nghttp2_hd_entry *ent;
|
||||||
nghttp2_hd_entry *ent;
|
ent = find_in_hd_table(deflater, &nv[i]);
|
||||||
ent = find_in_hd_table(deflater, &nv[i]);
|
if(ent) {
|
||||||
if(ent && find_in_workingset_by_index(deflater, ent->index) == NULL) {
|
ent->flags |= NGHTTP2_HD_FLAG_EMIT;
|
||||||
/* If nv[i] is found in hd_table and its index is not shadowed
|
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) {
|
||||||
by working set, use Indexed Header repr */
|
ent->flags |= NGHTTP2_HD_FLAG_REFSET;
|
||||||
rv = add_workingset(deflater, ent);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
rv = emit_indexed_block(buf_ptr, buflen_ptr, &offset, ent->index);
|
rv = emit_indexed_block(buf_ptr, buflen_ptr, &offset, ent->index);
|
||||||
if(rv < 0) {
|
if(rv < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t index = NGHTTP2_HD_INVALID_INDEX;
|
||||||
|
int incidx = 0;
|
||||||
|
ent = find_name_in_hd_table(deflater, &nv[i]);
|
||||||
|
if(ent) {
|
||||||
|
index = ent->index;
|
||||||
|
}
|
||||||
|
if(entry_room(nv[i].namelen, nv[i].valuelen)
|
||||||
|
< NGHTTP2_HD_MAX_ENTRY_SIZE) {
|
||||||
|
nghttp2_hd_entry *new_ent;
|
||||||
|
new_ent = add_hd_table_incremental(deflater, &nv[i]);
|
||||||
|
if(!new_ent) {
|
||||||
|
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
|
||||||
|
incidx = 1;
|
||||||
|
}
|
||||||
|
if(index == NGHTTP2_HD_INVALID_INDEX) {
|
||||||
|
rv = emit_newname_block(buf_ptr, buflen_ptr, &offset, &nv[i],
|
||||||
|
incidx);
|
||||||
} else {
|
} else {
|
||||||
/* Check name exists in hd_table */
|
rv = emit_indname_block(buf_ptr, buflen_ptr, &offset, index,
|
||||||
ent = find_name_in_hd_table(deflater, &nv[i]);
|
nv[i].value, nv[i].valuelen, incidx);
|
||||||
if(ent) {
|
}
|
||||||
uint8_t index = ent->index;
|
if(rv < 0) {
|
||||||
int incidx = 0;
|
goto fail;
|
||||||
if(entry_room(nv[i].namelen, nv[i].valuelen)
|
}
|
||||||
< NGHTTP2_HD_MAX_ENTRY_SIZE) {
|
}
|
||||||
nghttp2_hd_entry *new_ent;
|
}
|
||||||
new_ent = add_hd_table_incremental(deflater, &nv[i]);
|
|
||||||
if(!new_ent) {
|
for(i = 0; i < deflater->hd_tablelen; ++i) {
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
nghttp2_hd_entry *ent = deflater->hd_table[i];
|
||||||
goto fail;
|
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
|
||||||
}
|
if((ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
|
||||||
rv = add_workingset(deflater, new_ent);
|
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
|
||||||
if(rv < 0) {
|
rv = emit_indexed_block(buf_ptr, buflen_ptr, &offset, ent->index);
|
||||||
goto fail;
|
if(rv < 0) {
|
||||||
}
|
goto fail;
|
||||||
incidx = 1;
|
|
||||||
} else {
|
|
||||||
rv = add_workingset_indname(deflater, ent, nv[i].value,
|
|
||||||
nv[i].valuelen);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rv = emit_indname_block(buf_ptr, buflen_ptr, &offset, index,
|
|
||||||
nv[i].value, nv[i].valuelen, incidx);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int incidx = 0;
|
|
||||||
if(entry_room(nv[i].namelen, nv[i].valuelen)
|
|
||||||
< NGHTTP2_HD_MAX_ENTRY_SIZE) {
|
|
||||||
nghttp2_hd_entry *new_ent;
|
|
||||||
new_ent = add_hd_table_incremental(deflater, &nv[i]);
|
|
||||||
if(!new_ent) {
|
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
rv = add_workingset(deflater, new_ent);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
incidx = 1;
|
|
||||||
} else {
|
|
||||||
rv = add_workingset_newname(deflater, &nv[i]);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rv = emit_newname_block(buf_ptr, buflen_ptr, &offset, &nv[i],
|
|
||||||
incidx);
|
|
||||||
if(rv < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ent->flags &= ~NGHTTP2_HD_FLAG_EMIT;
|
||||||
}
|
}
|
||||||
return offset - nv_offset;
|
return offset - nv_offset;
|
||||||
fail:
|
fail:
|
||||||
|
@ -875,78 +771,38 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t build_nv_array(nghttp2_hd_context *inflater,
|
|
||||||
nghttp2_nv **nva_ptr)
|
|
||||||
{
|
|
||||||
int nvlen = 0, i;
|
|
||||||
nghttp2_nv *nv;
|
|
||||||
for(i = 0; i < inflater->wslen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ent = &inflater->ws[i];
|
|
||||||
if(ent->cat != NGHTTP2_HD_CAT_NONE) {
|
|
||||||
++nvlen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*nva_ptr = malloc(sizeof(nghttp2_nv)*nvlen);
|
|
||||||
if(*nva_ptr == NULL) {
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
nv = *nva_ptr;
|
|
||||||
for(i = 0; i < inflater->wslen; ++i) {
|
|
||||||
nghttp2_hd_ws_entry *ent = &inflater->ws[i];
|
|
||||||
switch(ent->cat) {
|
|
||||||
case NGHTTP2_HD_CAT_INDEXED:
|
|
||||||
*nv = ent->indexed.entry->nv;
|
|
||||||
++nv;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_INDNAME:
|
|
||||||
nv->name = ent->indname.entry->nv.name;
|
|
||||||
nv->namelen = ent->indname.entry->nv.namelen;
|
|
||||||
nv->value = ent->indname.value;
|
|
||||||
nv->valuelen = ent->indname.valuelen;
|
|
||||||
++nv;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_NEWNAME:
|
|
||||||
*nv = ent->newname.nv;
|
|
||||||
++nv;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nghttp2_nv_array_sort(*nva_ptr, nvlen);
|
|
||||||
return nvlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
size_t i;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
ssize_t nvlen = 0;
|
||||||
|
size_t nvacap = 0;
|
||||||
uint8_t *last = in + inlen;
|
uint8_t *last = in + inlen;
|
||||||
if(inflater->bad) {
|
if(inflater->bad) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
create_workingset(inflater);
|
*nva_ptr = NULL;
|
||||||
for(; in != last;) {
|
for(; in != last;) {
|
||||||
uint8_t c = *in;
|
uint8_t c = *in;
|
||||||
if(c & 0x80u) {
|
if(c & 0x80u) {
|
||||||
/* Indexed Header Repr */
|
/* Indexed Header Repr */
|
||||||
ssize_t index;
|
ssize_t index;
|
||||||
|
nghttp2_hd_entry *ent;
|
||||||
in = decode_length(&index, in, last, 7);
|
in = decode_length(&index, in, last, 7);
|
||||||
if(index < 0) {
|
if(index < 0) {
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* If nothing was removed, add entry from header table to
|
if(inflater->hd_tablelen <= index) {
|
||||||
workingset */
|
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||||
if(remove_from_workingset_by_index(inflater, index) == 0) {
|
goto fail;
|
||||||
nghttp2_hd_entry *ent;
|
}
|
||||||
if(inflater->hd_tablelen <= index) {
|
ent = inflater->hd_table[index];
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
|
||||||
goto fail;
|
if(ent->flags & NGHTTP2_HD_FLAG_REFSET) {
|
||||||
}
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen, ent);
|
||||||
ent = inflater->hd_table[index];
|
|
||||||
rv = add_workingset(inflater, ent);
|
|
||||||
if(rv < 0) {
|
if(rv < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -978,11 +834,12 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
in += valuelen;
|
in += valuelen;
|
||||||
nghttp2_downcase(nv.name, nv.namelen);
|
nghttp2_downcase(nv.name, nv.namelen);
|
||||||
if(c == 0x60u) {
|
if(c == 0x60u) {
|
||||||
rv = add_workingset_newname(inflater, &nv);
|
rv = emit_newname_header(inflater, nva_ptr, &nvacap, &nvlen, &nv);
|
||||||
} else {
|
} else {
|
||||||
nghttp2_hd_entry *ent = add_hd_table_incremental(inflater, &nv);
|
nghttp2_hd_entry *new_ent = add_hd_table_incremental(inflater, &nv);
|
||||||
if(ent) {
|
if(new_ent) {
|
||||||
rv = add_workingset(inflater, ent);
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen,
|
||||||
|
new_ent);
|
||||||
} else {
|
} else {
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1017,7 +874,8 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
value = in;
|
value = in;
|
||||||
in += valuelen;
|
in += valuelen;
|
||||||
if((c & 0x60u) == 0x60u) {
|
if((c & 0x60u) == 0x60u) {
|
||||||
rv = add_workingset_indname(inflater, ent, value, valuelen);
|
rv = emit_indname_header(inflater, nva_ptr, &nvacap, &nvlen, ent,
|
||||||
|
value, valuelen);
|
||||||
} else {
|
} else {
|
||||||
nghttp2_nv nv;
|
nghttp2_nv nv;
|
||||||
nghttp2_hd_entry *new_ent;
|
nghttp2_hd_entry *new_ent;
|
||||||
|
@ -1032,7 +890,8 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
free(ent);
|
free(ent);
|
||||||
}
|
}
|
||||||
if(new_ent) {
|
if(new_ent) {
|
||||||
rv = add_workingset(inflater, new_ent);
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen,
|
||||||
|
new_ent);
|
||||||
} else {
|
} else {
|
||||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1074,7 +933,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
nghttp2_downcase(nv.name, nv.namelen);
|
nghttp2_downcase(nv.name, nv.namelen);
|
||||||
new_ent = add_hd_table_subst(inflater, &nv, subindex);
|
new_ent = add_hd_table_subst(inflater, &nv, subindex);
|
||||||
if(new_ent) {
|
if(new_ent) {
|
||||||
rv = add_workingset(inflater, new_ent);
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen, new_ent);
|
||||||
if(rv < 0) {
|
if(rv < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1121,7 +980,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
free(ent);
|
free(ent);
|
||||||
}
|
}
|
||||||
if(new_ent) {
|
if(new_ent) {
|
||||||
rv = add_workingset(inflater, new_ent);
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen, new_ent);
|
||||||
if(rv < 0) {
|
if(rv < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1131,7 +990,19 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return build_nv_array(inflater, nva_ptr);
|
for(i = 0; i < inflater->hd_tablelen; ++i) {
|
||||||
|
nghttp2_hd_entry *ent = inflater->hd_table[i];
|
||||||
|
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) &&
|
||||||
|
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
|
||||||
|
rv = emit_indexed_header(inflater, nva_ptr, &nvacap, &nvlen, ent);
|
||||||
|
if(rv < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ent->flags &= ~NGHTTP2_HD_FLAG_EMIT;
|
||||||
|
}
|
||||||
|
nghttp2_nv_array_sort(*nva_ptr, nvlen);
|
||||||
|
return nvlen;
|
||||||
fail:
|
fail:
|
||||||
inflater->bad = 1;
|
inflater->bad = 1;
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -1139,36 +1010,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
|
|
||||||
int nghttp2_hd_end_headers(nghttp2_hd_context *context)
|
int nghttp2_hd_end_headers(nghttp2_hd_context *context)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
uint8_t checks[128];
|
for(i = 0; i < context->emit_setlen; ++i) {
|
||||||
memset(checks, 0, sizeof(checks));
|
nghttp2_hd_entry *ent = context->emit_set[i];
|
||||||
assert(context->refsetlen == 0);
|
if(--ent->ref == 0) {
|
||||||
for(i = 0; i < context->wslen; ++i) {
|
nghttp2_hd_entry_free(ent);
|
||||||
nghttp2_hd_ws_entry *ws_ent = &context->ws[i];
|
free(ent);
|
||||||
switch(ws_ent->cat) {
|
|
||||||
case NGHTTP2_HD_CAT_INDEXED:
|
|
||||||
if(ws_ent->indexed.entry->index != NGHTTP2_HD_INVALID_INDEX &&
|
|
||||||
checks[ws_ent->indexed.entry->index] == 0) {
|
|
||||||
checks[ws_ent->indexed.entry->index] = 1;
|
|
||||||
context->refset[context->refsetlen++] = ws_ent->indexed.entry;
|
|
||||||
} else {
|
|
||||||
if(--ws_ent->indexed.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ws_ent->indexed.entry);
|
|
||||||
free(ws_ent->indexed.entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NGHTTP2_HD_CAT_INDNAME:
|
|
||||||
if(--ws_ent->indname.entry->ref == 0) {
|
|
||||||
nghttp2_hd_entry_free(ws_ent->indname.entry);
|
|
||||||
free(ws_ent->indname.entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context->wslen = 0;
|
context->emit_setlen = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,7 @@
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
#define NGHTTP2_INITIAL_HD_TABLE_SIZE 128
|
#define NGHTTP2_INITIAL_HD_TABLE_SIZE 128
|
||||||
#define NGHTTP2_INITIAL_REFSET_SIZE 128
|
#define NGHTTP2_INITIAL_EMIT_SET_SIZE 128
|
||||||
#define NGHTTP2_INITIAL_WS_SIZE 128
|
|
||||||
|
|
||||||
#define NGHTTP2_HD_MAX_BUFFER_SIZE 4096
|
#define NGHTTP2_HD_MAX_BUFFER_SIZE 4096
|
||||||
#define NGHTTP2_HD_MAX_ENTRY_SIZE 1024
|
#define NGHTTP2_HD_MAX_ENTRY_SIZE 1024
|
||||||
|
@ -54,6 +53,11 @@ typedef enum {
|
||||||
NGHTTP2_HD_FLAG_NAME_ALLOC = 1,
|
NGHTTP2_HD_FLAG_NAME_ALLOC = 1,
|
||||||
/* Indicates value was dynamically allocated and must be freed */
|
/* Indicates value was dynamically allocated and must be freed */
|
||||||
NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1,
|
NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1,
|
||||||
|
/* Indicates that the entry is in the reference set */
|
||||||
|
NGHTTP2_HD_FLAG_REFSET = 1 << 2,
|
||||||
|
/* Indicates that the entry is emitted in the current header
|
||||||
|
processing. */
|
||||||
|
NGHTTP2_HD_FLAG_EMIT = 1 << 3,
|
||||||
} nghttp2_hd_flags;
|
} nghttp2_hd_flags;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -65,54 +69,20 @@ typedef struct {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} nghttp2_hd_entry;
|
} nghttp2_hd_entry;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
NGHTTP2_HD_CAT_NONE,
|
|
||||||
NGHTTP2_HD_CAT_INDEXED,
|
|
||||||
NGHTTP2_HD_CAT_INDNAME,
|
|
||||||
NGHTTP2_HD_CAT_NEWNAME
|
|
||||||
} nghttp2_hd_entry_cat;
|
|
||||||
|
|
||||||
typedef struct nghttp2_hd_ws_entry {
|
|
||||||
nghttp2_hd_entry_cat cat;
|
|
||||||
union {
|
|
||||||
/* For NGHTTP2_HD_CAT_INDEXED */
|
|
||||||
struct {
|
|
||||||
nghttp2_hd_entry *entry;
|
|
||||||
uint8_t index;
|
|
||||||
} indexed;
|
|
||||||
/* For NGHTTP2_HD_CAT_NEWNAME */
|
|
||||||
struct {
|
|
||||||
nghttp2_nv nv;
|
|
||||||
} newname;
|
|
||||||
/* For NGHTTP2_HD_CAT_LITERAL_INDNAME */
|
|
||||||
struct {
|
|
||||||
/* The entry in header table the name stored */
|
|
||||||
nghttp2_hd_entry *entry;
|
|
||||||
uint8_t *value;
|
|
||||||
uint16_t valuelen;
|
|
||||||
} indname;
|
|
||||||
};
|
|
||||||
} nghttp2_hd_ws_entry;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Header table */
|
/* Header table */
|
||||||
nghttp2_hd_entry **hd_table;
|
nghttp2_hd_entry **hd_table;
|
||||||
/* Reference set */
|
/* Holding emitted entry in deflating header block to retain
|
||||||
nghttp2_hd_entry **refset;
|
reference count. */
|
||||||
/* Working set */
|
nghttp2_hd_entry **emit_set;
|
||||||
nghttp2_hd_ws_entry *ws;
|
|
||||||
/* The capacity of the |hd_table| */
|
/* The capacity of the |hd_table| */
|
||||||
uint16_t hd_table_capacity;
|
uint16_t hd_table_capacity;
|
||||||
/* the number of entry the |hd_table| contains */
|
/* The number of entry the |hd_table| contains */
|
||||||
uint16_t hd_tablelen;
|
uint16_t hd_tablelen;
|
||||||
/* The capacity of the |refset| */
|
/* The capacity of the |emit_set| */
|
||||||
uint16_t refset_capacity;
|
uint16_t emit_set_capacity;
|
||||||
/* The number of entry the |refset| contains */
|
/* The number of entry the |emit_set| contains */
|
||||||
uint16_t refsetlen;
|
uint16_t emit_setlen;
|
||||||
/* The capacity of the |ws| */
|
|
||||||
uint16_t ws_capacity;
|
|
||||||
/* The number of entry the |ws| contains */
|
|
||||||
uint16_t wslen;
|
|
||||||
/* Abstract buffer size of hd_table as described in the spec. This
|
/* Abstract buffer size of hd_table as described in the spec. This
|
||||||
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. */
|
||||||
|
@ -218,8 +188,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
|
||||||
uint8_t *in, size_t inlen);
|
uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signals the end of processing one header block. This function
|
* Signals the end of processing one header block.
|
||||||
* creates new reference set from working set.
|
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds. Currently this function
|
* This function returns 0 if it succeeds. Currently this function
|
||||||
* always succeeds.
|
* always succeeds.
|
||||||
|
|
|
@ -227,7 +227,7 @@ int main(int argc, char* argv[])
|
||||||
!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",
|
!CU_add_test(pSuite, "hd_inflate_indname_subst",
|
||||||
test_nghttp2_hd_inflate_newname_inc) ||
|
test_nghttp2_hd_inflate_indname_subst) ||
|
||||||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction",
|
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction",
|
||||||
test_nghttp2_hd_inflate_indname_subst_eviction) ||
|
test_nghttp2_hd_inflate_indname_subst_eviction) ||
|
||||||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction_neg",
|
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction_neg",
|
||||||
|
|
|
@ -156,11 +156,11 @@ void test_nghttp2_hd_inflate_indname_inc(void)
|
||||||
nghttp2_nv *resnva;
|
nghttp2_nv *resnva;
|
||||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
|
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 12,
|
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 11,
|
||||||
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(39 == inflater.hd_tablelen);
|
CU_ASSERT(31 == inflater.hd_tablelen);
|
||||||
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
|
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
|
||||||
|
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
|
@ -174,13 +174,14 @@ 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 1592. Adding 2547 bytes,
|
/* Default header table capacity is 1262. Adding 2835 bytes,
|
||||||
including overhead, to the table evicts first entry.
|
including overhead, to the table evicts first entry.
|
||||||
use name ":host" which index 2 and value length 2510. */
|
use name ":host" which index 2 and value length 2798. */
|
||||||
uint8_t value[2510];
|
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));
|
||||||
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(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
|
||||||
|
@ -191,8 +192,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(38 == inflater.hd_tablelen);
|
CU_ASSERT(30 == inflater.hd_tablelen);
|
||||||
CU_ASSERT(37 == inflater.refset[0]->index);
|
CU_ASSERT(inflater.hd_table[29]->flags & NGHTTP2_HD_FLAG_REFSET);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
nghttp2_hd_inflate_free(&inflater);
|
nghttp2_hd_inflate_free(&inflater);
|
||||||
|
@ -212,7 +213,7 @@ 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(39 == inflater.hd_tablelen);
|
CU_ASSERT(31 == inflater.hd_tablelen);
|
||||||
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
|
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
|
||||||
|
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
|
@ -231,13 +232,13 @@ void test_nghttp2_hd_inflate_indname_subst(void)
|
||||||
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
|
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
||||||
12,
|
11,
|
||||||
nv.value, nv.valuelen,
|
nv.value, nv.valuelen,
|
||||||
12));
|
11));
|
||||||
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(38 == inflater.hd_tablelen);
|
CU_ASSERT(30 == inflater.hd_tablelen);
|
||||||
assert_nv_equal(&nv, &inflater.hd_table[12]->nv, 1);
|
assert_nv_equal(&nv, &inflater.hd_table[11]->nv, 1);
|
||||||
|
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
@ -250,13 +251,14 @@ void test_nghttp2_hd_inflate_indname_subst_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 1592. Adding 2547 bytes,
|
/* Default header table capacity is 1262. Adding 2877 bytes,
|
||||||
including overhead, to the table evicts first entry.
|
including overhead, to the table evicts first entry.
|
||||||
use name ":host" which index 2 and value length 2510. */
|
use name ":host" which index 2 and value length 2840. */
|
||||||
uint8_t value[2510];
|
uint8_t value[2840];
|
||||||
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));
|
||||||
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
||||||
2,
|
2,
|
||||||
value, sizeof(value), 2));
|
value, sizeof(value), 2));
|
||||||
|
@ -268,8 +270,8 @@ void test_nghttp2_hd_inflate_indname_subst_eviction(void)
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
nghttp2_hd_end_headers(&inflater);
|
nghttp2_hd_end_headers(&inflater);
|
||||||
|
|
||||||
CU_ASSERT(37 == inflater.hd_tablelen);
|
CU_ASSERT(29 == inflater.hd_tablelen);
|
||||||
CU_ASSERT(1 == inflater.refset[0]->index);
|
CU_ASSERT(inflater.hd_table[1]->flags & NGHTTP2_HD_FLAG_REFSET);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
nghttp2_hd_inflate_free(&inflater);
|
nghttp2_hd_inflate_free(&inflater);
|
||||||
|
@ -281,12 +283,13 @@ void test_nghttp2_hd_inflate_indname_subst_eviction_neg(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 1592. Adding 2548 bytes,
|
/* Default header table capacity is 1262. Adding 2878 bytes,
|
||||||
including overhead, to the table evicts first entry.
|
including overhead, to the table evicts first 2 entries.
|
||||||
use name ":host" which index 2 and value length 2511. */
|
use name ":host" which index 2 and value length 2841. */
|
||||||
uint8_t value[2511];
|
uint8_t value[2841];
|
||||||
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));
|
||||||
/* Try to substitute index 0, but it will be evicted */
|
/* Try to substitute index 0, but it will be evicted */
|
||||||
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
|
||||||
2,
|
2,
|
||||||
|
@ -299,8 +302,8 @@ void test_nghttp2_hd_inflate_indname_subst_eviction_neg(void)
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
nghttp2_hd_end_headers(&inflater);
|
nghttp2_hd_end_headers(&inflater);
|
||||||
|
|
||||||
CU_ASSERT(37 == inflater.hd_tablelen);
|
CU_ASSERT(29 == inflater.hd_tablelen);
|
||||||
CU_ASSERT(0 == inflater.refset[0]->index);
|
CU_ASSERT(inflater.hd_table[0]->flags & NGHTTP2_HD_FLAG_REFSET);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
nghttp2_hd_inflate_free(&inflater);
|
nghttp2_hd_inflate_free(&inflater);
|
||||||
|
@ -320,7 +323,7 @@ void test_nghttp2_hd_inflate_newname_subst(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(38 == inflater.hd_tablelen);
|
CU_ASSERT(30 == inflater.hd_tablelen);
|
||||||
assert_nv_equal(&nv, &inflater.hd_table[1]->nv, 1);
|
assert_nv_equal(&nv, &inflater.hd_table[1]->nv, 1);
|
||||||
|
|
||||||
nghttp2_nv_array_del(resnva);
|
nghttp2_nv_array_del(resnva);
|
||||||
|
|
Loading…
Reference in New Issue