diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 1a0e5a3c..bdfa16aa 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -708,12 +708,12 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, 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); + 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->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(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) { /* Emit common header just before it slips away from the table. If we don't do this, we have to emit it in literal @@ -730,45 +730,43 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, free(ent); } } - if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { - 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; + 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; } - 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; + 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; } } @@ -816,8 +814,7 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, context->hd_table_bufsize += room; new_ent->flags |= NGHTTP2_HD_FLAG_REFSET; nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent); - if(context->role == NGHTTP2_HD_ROLE_DEFLATE && - room <= context->deflate_hd_table_bufsize_max) { + if(room <= context->deflate_hd_table_bufsize_max) { context->deflate_hd_table_bufsize += room; ++context->deflate_hd_tablelen; } @@ -828,9 +825,7 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, static ssize_t find_in_hd_table(nghttp2_hd_context *context, nghttp2_nv *nv) { size_t i; - size_t max = context->role == NGHTTP2_HD_ROLE_DEFLATE ? - context->deflate_hd_tablelen : context->hd_table.len; - for(i = 0; i < max; ++i) { + for(i = 0; i < context->deflate_hd_tablelen; ++i) { nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i); if(nghttp2_nv_equal(&ent->nv, nv)) { return i; @@ -849,9 +844,7 @@ static ssize_t find_name_in_hd_table(nghttp2_hd_context *context, nghttp2_nv *nv) { size_t i; - size_t max = context->role == NGHTTP2_HD_ROLE_DEFLATE ? - context->deflate_hd_tablelen : context->hd_table.len; - for(i = 0; i < max; ++i) { + for(i = 0; i < context->deflate_hd_tablelen; ++i) { nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i); if(ent->nv.namelen == nv->namelen && memcmp(ent->nv.name, nv->name, nv->namelen) == 0) { @@ -878,17 +871,18 @@ int nghttp2_hd_change_table_size(nghttp2_hd_context *context, 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 && context->hd_table.len > 0) { 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); - if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { - 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->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); if(--ent->ref == 0) { diff --git a/lib/nghttp2_hd.h b/lib/nghttp2_hd.h index f82aa6b4..4363ed9b 100644 --- a/lib/nghttp2_hd.h +++ b/lib/nghttp2_hd.h @@ -93,18 +93,22 @@ typedef struct { /* The header table size for decoding. If the context is initialized as encoder, this value is advertised by remote endpoint decoder. */ + size_t hd_table_bufsize; + /* If inflate/deflate error occurred, this value is set to 1 and + further invocation of inflate/deflate will fail with + NGHTTP2_ERR_HEADER_COMP. */ size_t hd_table_bufsize_max; /* The current effective header table size for encoding. This value - is meaningful iff this context is initialized as - encoder. |deflate_hd_table_bufsize| <= |hd_table_bufsize| must be + 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 meaningful iff this context is initialized - as encoder. */ + 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|. */ size_t deflate_hd_tablelen; @@ -118,10 +122,6 @@ typedef struct { /* Abstract buffer size of hd_table as described in the spec. This is the sum of length of name/value in hd_table + NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */ - size_t hd_table_bufsize; - /* If inflate/deflate error occurred, this value is set to 1 and - further invocation of inflate/deflate will fail with - NGHTTP2_ERR_HEADER_COMP. */ uint8_t bad; /* Role of this context; deflate or infalte */ nghttp2_hd_role role;