Always allocate buffer for name, and value

This commit is contained in:
Tatsuhiro Tsujikawa 2016-03-11 01:52:55 +09:00
parent eb393985b7
commit 8da20975f9
5 changed files with 97 additions and 243 deletions

View File

@ -73,7 +73,7 @@ typedef struct {
/* /*
* Initializes the |buf|. No memory is allocated in this function. Use * Initializes the |buf|. No memory is allocated in this function. Use
* nghttp2_buf_reserve() or nghttp2_buf_reserve2() to allocate memory. * nghttp2_buf_reserve() to allocate memory.
*/ */
void nghttp2_buf_init(nghttp2_buf *buf); void nghttp2_buf_init(nghttp2_buf *buf);

View File

@ -1099,30 +1099,24 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) {
inflater->min_hd_table_bufsize_max = UINT32_MAX; inflater->min_hd_table_bufsize_max = UINT32_MAX;
inflater->ent_keep = NULL; inflater->ent_keep = NULL;
inflater->nv_keep = NULL; inflater->nv_name_keep = NULL;
inflater->nv_value_keep = NULL;
inflater->opcode = NGHTTP2_HD_OPCODE_NONE; inflater->opcode = NGHTTP2_HD_OPCODE_NONE;
inflater->state = NGHTTP2_HD_STATE_INFLATE_START; inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
rv = nghttp2_bufs_init3(&inflater->nvbufs, NGHTTP2_HD_MAX_NV / 8, 8, 1, 0, nghttp2_buf_init(&inflater->namebuf);
mem); nghttp2_buf_init(&inflater->valuebuf);
if (rv != 0) {
goto nvbufs_fail;
}
inflater->huffman_encoded = 0; inflater->huffman_encoded = 0;
inflater->index = 0; inflater->index = 0;
inflater->left = 0; inflater->left = 0;
inflater->shift = 0; inflater->shift = 0;
inflater->newnamelen = 0;
inflater->index_required = 0; inflater->index_required = 0;
inflater->no_index = 0; inflater->no_index = 0;
return 0; return 0;
nvbufs_fail:
hd_context_free(&inflater->ctx);
fail: fail:
return rv; return rv;
} }
@ -1139,8 +1133,11 @@ static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) {
inflater->ent_keep = NULL; inflater->ent_keep = NULL;
} }
nghttp2_mem_free(mem, inflater->nv_keep); nghttp2_mem_free(mem, inflater->nv_value_keep);
inflater->nv_keep = NULL; inflater->nv_value_keep = NULL;
nghttp2_mem_free(mem, inflater->nv_name_keep);
inflater->nv_name_keep = NULL;
} }
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) { void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) {
@ -1148,8 +1145,13 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) {
} }
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) { void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) {
nghttp2_mem *mem;
mem = inflater->ctx.mem;
hd_inflate_keep_free(inflater); hd_inflate_keep_free(inflater);
nghttp2_bufs_free(&inflater->nvbufs); nghttp2_buf_free(&inflater->valuebuf, mem);
nghttp2_buf_free(&inflater->namebuf, mem);
hd_context_free(&inflater->ctx); hd_context_free(&inflater->ctx);
} }
@ -2036,11 +2038,9 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin,
* Out of memory * Out of memory
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Huffman decoding failed * Huffman decoding failed
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/ */
static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
nghttp2_bufs *bufs, uint8_t *in, nghttp2_buf *buf, uint8_t *in,
uint8_t *last) { uint8_t *last) {
ssize_t readlen; ssize_t readlen;
int final = 0; int final = 0;
@ -2048,7 +2048,7 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
last = in + inflater->left; last = in + inflater->left;
final = 1; final = 1;
} }
readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, bufs, in, readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in,
(size_t)(last - in), final); (size_t)(last - in), final);
if (readlen < 0) { if (readlen < 0) {
@ -2070,17 +2070,13 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
* Out of memory * Out of memory
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Header decompression failed * Header decompression failed
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/ */
static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf,
nghttp2_bufs *bufs, uint8_t *in, uint8_t *last) { uint8_t *in, uint8_t *last) {
int rv;
size_t len = nghttp2_min((size_t)(last - in), inflater->left); size_t len = nghttp2_min((size_t)(last - in), inflater->left);
rv = nghttp2_bufs_add(bufs, in, len);
if (rv != 0) { buf->last = nghttp2_cpymem(buf->last, in, len);
return rv;
}
inflater->left -= len; inflater->left -= len;
return (ssize_t)len; return (ssize_t)len;
} }
@ -2105,112 +2101,6 @@ static int hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
return 0; return 0;
} }
static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
int value_only) {
ssize_t rv;
size_t buflen;
uint8_t *buf;
nghttp2_buf *pbuf;
if (inflater->index_required ||
inflater->nvbufs.head != inflater->nvbufs.cur) {
rv = nghttp2_bufs_remove(&inflater->nvbufs, &buf);
if (rv < 0) {
return NGHTTP2_ERR_NOMEM;
}
nghttp2_bufs_reset(&inflater->nvbufs);
buflen = (size_t)rv;
if (value_only) {
/* we don't use this value, so no need to NULL-terminate */
nv->name = NULL;
nv->namelen = 0;
nv->value = buf;
nv->valuelen = buflen - 1;
} else {
nv->name = buf;
nv->namelen = inflater->newnamelen;
nv->value = buf + nv->namelen + 1;
nv->valuelen = buflen - nv->namelen - 2;
}
return 0;
}
/* If we are not going to store header in header table and
name/value are in first chunk, we just refer them from nv,
instead of mallocing another memory. */
pbuf = &inflater->nvbufs.head->buf;
if (value_only) {
/* we don't use this value, so no need to NULL-terminate */
nv->name = NULL;
nv->namelen = 0;
nv->value = pbuf->pos;
nv->valuelen = nghttp2_buf_len(pbuf) - 1;
} else {
nv->name = pbuf->pos;
nv->namelen = inflater->newnamelen;
nv->value = pbuf->pos + nv->namelen + 1;
nv->valuelen = nghttp2_buf_len(pbuf) - nv->namelen - 2;
}
/* Resetting does not change the content of first buffer */
nghttp2_bufs_reset(&inflater->nvbufs);
return 0;
}
static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv,
nghttp2_hd_entry *ent_name) {
#ifndef NDEBUG
size_t rv;
#endif
size_t buflen;
uint8_t *buf;
nghttp2_mem *mem;
mem = inflater->ctx.mem;
/* Allocate buffer including name in ent_name, plus terminating
NULL. */
buflen = ent_name->nv.namelen + 1 + nghttp2_bufs_len(&inflater->nvbufs);
buf = nghttp2_mem_malloc(mem, buflen);
if (buf == NULL) {
return NGHTTP2_ERR_NOMEM;
}
/* Copy including terminal NULL */
memcpy(buf, ent_name->nv.name, ent_name->nv.namelen + 1);
#ifndef NDEBUG
rv =
#endif
nghttp2_bufs_remove_copy(&inflater->nvbufs,
buf + ent_name->nv.namelen + 1);
assert(ent_name->nv.namelen + 1 + rv == buflen);
nghttp2_bufs_reset(&inflater->nvbufs);
nv->name = buf;
nv->namelen = ent_name->nv.namelen;
nv->value = buf + nv->namelen + 1;
nv->valuelen = buflen - nv->namelen - 2;
return 0;
}
/* /*
* Finalize literal header representation - new name- reception. If * Finalize literal header representation - new name- reception. If
* header is emitted, |*nv_out| is filled with that value and 0 is * header is emitted, |*nv_out| is filled with that value and 0 is
@ -2224,16 +2114,18 @@ static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
*/ */
static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *token_out) { nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv; nghttp2_nv nv;
nghttp2_mem *mem; nghttp2_mem *mem;
mem = inflater->ctx.mem; mem = inflater->ctx.mem;
rv = hd_inflate_remove_bufs(inflater, &nv, 0 /* name and value */); nv.name = inflater->namebuf.pos;
if (rv != 0) { nv.namelen = nghttp2_buf_len(&inflater->namebuf);
return NGHTTP2_ERR_NOMEM; nv.value = inflater->valuebuf.pos;
} nv.valuelen = nghttp2_buf_len(&inflater->valuebuf);
nghttp2_buf_init(&inflater->valuebuf);
nghttp2_buf_init(&inflater->namebuf);
if (inflater->no_index) { if (inflater->no_index) {
nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
@ -2245,10 +2137,8 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
uint8_t ent_flags; uint8_t ent_flags;
/* nv->value points to the middle of the buffer pointed by ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT |
nv->name. So we just need to keep track of nv->name for memory NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT;
management. */
ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT;
new_ent = add_hd_table_incremental(&inflater->ctx, &nv, new_ent = add_hd_table_incremental(&inflater->ctx, &nv,
lookup_token(nv.name, nv.namelen), lookup_token(nv.name, nv.namelen),
@ -2261,6 +2151,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
return 0; return 0;
} }
nghttp2_mem_free(mem, nv.value);
nghttp2_mem_free(mem, nv.name); nghttp2_mem_free(mem, nv.name);
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
@ -2268,9 +2159,8 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
emit_literal_header(nv_out, token_out, &nv); emit_literal_header(nv_out, token_out, &nv);
if (nv.name != inflater->nvbufs.head->buf.pos) { inflater->nv_name_keep = nv.name;
inflater->nv_keep = nv.name; inflater->nv_value_keep = nv.value;
}
return 0; return 0;
} }
@ -2288,7 +2178,6 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
*/ */
static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *token_out) { nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv; nghttp2_nv nv;
nghttp2_hd_entry *ent_name; nghttp2_hd_entry *ent_name;
nghttp2_mem *mem; nghttp2_mem *mem;
@ -2307,24 +2196,20 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
uint8_t ent_flags; uint8_t ent_flags;
if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) { ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT;
if (inflater->index >= NGHTTP2_STATIC_TABLE_LENGTH) {
/* We don't copy name in static table */ /* We don't copy name in static table */
rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */); ent_flags |= NGHTTP2_HD_FLAG_NAME_ALLOC;
if (rv != 0) {
return NGHTTP2_ERR_NOMEM;
} }
nv.name = ent_name->nv.name; nv.name = ent_name->nv.name;
nv.namelen = ent_name->nv.namelen; nv.namelen = ent_name->nv.namelen;
ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT; nv.value = inflater->valuebuf.pos;
} else { nv.valuelen = nghttp2_buf_len(&inflater->valuebuf);
rv = hd_inflate_remove_bufs_with_name(inflater, &nv, ent_name);
if (rv != 0) { nghttp2_buf_init(&inflater->valuebuf);
return NGHTTP2_ERR_NOMEM;
}
/* nv->name and nv->value are in the same buffer. */
ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT;
}
new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token, new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token,
ent_flags, NULL, 0); ent_flags, NULL, 0);
@ -2339,28 +2224,21 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
return 0; return 0;
} }
if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) {
nghttp2_mem_free(mem, nv.value); nghttp2_mem_free(mem, nv.value);
} else {
nghttp2_mem_free(mem, nv.name);
}
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */);
if (rv != 0) {
return NGHTTP2_ERR_NOMEM;
}
nv.name = ent_name->nv.name; nv.name = ent_name->nv.name;
nv.namelen = ent_name->nv.namelen; nv.namelen = ent_name->nv.namelen;
nv.value = inflater->valuebuf.pos;
nv.valuelen = nghttp2_buf_len(&inflater->valuebuf);
nghttp2_buf_init(&inflater->valuebuf);
emit_literal_header(nv_out, token_out, &nv); emit_literal_header(nv_out, token_out, &nv);
if (nv.value != inflater->nvbufs.head->buf.pos) { inflater->nv_value_keep = nv.value;
inflater->nv_keep = nv.value;
}
return 0; return 0;
} }
@ -2383,6 +2261,9 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
uint8_t *last = in + inlen; uint8_t *last = in + inlen;
int rfin = 0; int rfin = 0;
int busy = 0; int busy = 0;
nghttp2_mem *mem;
mem = inflater->ctx.mem;
if (inflater->ctx.bad) { if (inflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
@ -2541,12 +2422,20 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF; inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
rv = nghttp2_buf_reserve(&inflater->namebuf, inflater->left * 2 + 1,
mem);
} else { } else {
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME; inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
rv = nghttp2_buf_reserve(&inflater->namebuf, inflater->left + 1, mem);
} }
if (rv != 0) {
goto fail;
}
break; break;
case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF: case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF:
rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last); rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last);
if (rv < 0) { if (rv < 0) {
goto fail; goto fail;
} }
@ -2562,18 +2451,13 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
goto almost_ok; goto almost_ok;
} }
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs); *inflater->namebuf.last = '\0';
rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
if (rv != 0) {
goto fail;
}
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
break; break;
case NGHTTP2_HD_STATE_NEWNAME_READ_NAME: case NGHTTP2_HD_STATE_NEWNAME_READ_NAME:
rv = hd_inflate_read(inflater, &inflater->nvbufs, in, last); rv = hd_inflate_read(inflater, &inflater->namebuf, in, last);
if (rv < 0) { if (rv < 0) {
goto fail; goto fail;
} }
@ -2588,12 +2472,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
goto almost_ok; goto almost_ok;
} }
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs); *inflater->namebuf.last = '\0';
rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
if (rv != 0) {
goto fail;
}
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
@ -2625,15 +2504,24 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
rv = nghttp2_buf_reserve(&inflater->valuebuf, inflater->left * 2 + 1,
mem);
} else { } else {
inflater->state = NGHTTP2_HD_STATE_READ_VALUE; inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
rv = nghttp2_buf_reserve(&inflater->valuebuf, inflater->left + 1, mem);
}
if (rv != 0) {
goto fail;
} }
busy = 1; busy = 1;
break; break;
case NGHTTP2_HD_STATE_READ_VALUEHUFF: case NGHTTP2_HD_STATE_READ_VALUEHUFF:
rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last); rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last);
if (rv < 0) { if (rv < 0) {
goto fail; goto fail;
} }
@ -2649,10 +2537,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
goto almost_ok; goto almost_ok;
} }
rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); *inflater->valuebuf.last = '\0';
if (rv != 0) {
goto fail;
}
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
rv = hd_inflate_commit_newname(inflater, nv_out, token_out); rv = hd_inflate_commit_newname(inflater, nv_out, token_out);
@ -2669,7 +2554,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
return (ssize_t)(in - first); return (ssize_t)(in - first);
case NGHTTP2_HD_STATE_READ_VALUE: case NGHTTP2_HD_STATE_READ_VALUE:
rv = hd_inflate_read(inflater, &inflater->nvbufs, in, last); rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last);
if (rv < 0) { if (rv < 0) {
DEBUGF(fprintf(stderr, "inflatehd: value read failure %zd: %s\n", rv, DEBUGF(fprintf(stderr, "inflatehd: value read failure %zd: %s\n", rv,
nghttp2_strerror((int)rv))); nghttp2_strerror((int)rv)));
@ -2686,10 +2571,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
goto almost_ok; goto almost_ok;
} }
rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); *inflater->valuebuf.last = '\0';
if (rv != 0) {
goto fail;
}
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
rv = hd_inflate_commit_newname(inflater, nv_out, token_out); rv = hd_inflate_commit_newname(inflater, nv_out, token_out);

View File

@ -276,7 +276,7 @@ struct nghttp2_hd_deflater {
struct nghttp2_hd_inflater { struct nghttp2_hd_inflater {
nghttp2_hd_context ctx; nghttp2_hd_context ctx;
/* header buffer */ /* header buffer */
nghttp2_bufs nvbufs; nghttp2_buf namebuf, valuebuf;
/* Stores current state of huffman decoding */ /* Stores current state of huffman decoding */
nghttp2_hd_huff_decode_context huff_decode_ctx; nghttp2_hd_huff_decode_context huff_decode_ctx;
/* Pointer to the nghttp2_hd_entry which is used current header /* Pointer to the nghttp2_hd_entry which is used current header
@ -285,14 +285,11 @@ struct nghttp2_hd_inflater {
nghttp2_hd_entry *ent_keep; nghttp2_hd_entry *ent_keep;
/* Pointer to the name/value pair buffer which is used in the /* Pointer to the name/value pair buffer which is used in the
current header emission. */ current header emission. */
uint8_t *nv_keep; uint8_t *nv_name_keep, *nv_value_keep;
/* The number of bytes to read */ /* The number of bytes to read */
size_t left; size_t left;
/* The index in indexed repr or indexed name */ /* The index in indexed repr or indexed name */
size_t index; size_t index;
/* The length of new name encoded in literal. For huffman encoded
string, this is the length after it is decoded. */
size_t newnamelen;
/* The maximum header table size the inflater supports. This is the /* The maximum header table size the inflater supports. This is the
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
size_t settings_hd_table_bufsize_max; size_t settings_hd_table_bufsize_max;
@ -472,9 +469,8 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
/* /*
* Decodes the given data |src| with length |srclen|. The |ctx| must * Decodes the given data |src| with length |srclen|. The |ctx| must
* be initialized by nghttp2_hd_huff_decode_context_init(). The result * be initialized by nghttp2_hd_huff_decode_context_init(). The result
* will be added to |dest|. This function may expand |dest| as * will be written to |buf|. This function assumes that |buf| has the
* needed. The caller is responsible to release the memory of |dest| * enough room to store the decoded byte string.
* by calling nghttp2_bufs_free().
* *
* The caller must set the |final| to nonzero if the given input is * The caller must set the |final| to nonzero if the given input is
* the final block. * the final block.
@ -486,13 +482,11 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
* *
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Maximum buffer capacity size exceeded.
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* Decoding process has failed. * Decoding process has failed.
*/ */
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_bufs *bufs, const uint8_t *src, nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int final); size_t srclen, int final);
#endif /* NGHTTP2_HD_H */ #endif /* NGHTTP2_HD_H */

View File

@ -166,31 +166,10 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
ctx->accept = 1; ctx->accept = 1;
} }
/* Use macro to make the code simpler..., but error case is tricky.
We spent most of the CPU in decoding, so we are doing this
thing. */
#define hd_huff_decode_sym_emit(bufs, sym, avail) \
do { \
if ((avail)) { \
nghttp2_bufs_fast_addb((bufs), (sym)); \
--(avail); \
} else { \
rv = nghttp2_bufs_addb((bufs), (sym)); \
if (rv != 0) { \
return rv; \
} \
(avail) = nghttp2_bufs_cur_avail((bufs)); \
} \
} while (0)
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_bufs *bufs, const uint8_t *src, nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int final) { size_t srclen, int final) {
size_t i; size_t i;
int rv;
size_t avail;
avail = nghttp2_bufs_cur_avail(bufs);
/* We use the decoding algorithm described in /* We use the decoding algorithm described in
http://graphics.ics.uci.edu/pub/Prefix.pdf */ http://graphics.ics.uci.edu/pub/Prefix.pdf */
@ -202,8 +181,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
if (t->flags & NGHTTP2_HUFF_SYM) { if (t->flags & NGHTTP2_HUFF_SYM) {
/* this is macro, and may return from this function on error */ *buf->last++ = t->sym;
hd_huff_decode_sym_emit(bufs, t->sym, avail);
} }
t = &huff_decode_table[t->state][src[i] & 0xf]; t = &huff_decode_table[t->state][src[i] & 0xf];
@ -211,8 +189,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
if (t->flags & NGHTTP2_HUFF_SYM) { if (t->flags & NGHTTP2_HUFF_SYM) {
/* this is macro, and may return from this function on error */ *buf->last++ = t->sym;
hd_huff_decode_sym_emit(bufs, t->sym, avail);
} }
ctx->state = t->state; ctx->state = t->state;

View File

@ -1352,13 +1352,15 @@ void test_nghttp2_hd_decode_length(void) {
void test_nghttp2_hd_huff_encode(void) { void test_nghttp2_hd_huff_encode(void) {
int rv; int rv;
ssize_t len; ssize_t len;
nghttp2_bufs bufs, outbufs; nghttp2_buf outbuf;
nghttp2_bufs bufs;
nghttp2_hd_huff_decode_context ctx; nghttp2_hd_huff_decode_context ctx;
const uint8_t t1[] = {22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, const uint8_t t1[] = {22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11,
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
uint8_t b[256];
nghttp2_buf_wrap_init(&outbuf, b, sizeof(b));
frame_pack_bufs_init(&bufs); frame_pack_bufs_init(&bufs);
frame_pack_bufs_init(&outbufs);
rv = nghttp2_hd_huff_encode(&bufs, t1, sizeof(t1)); rv = nghttp2_hd_huff_encode(&bufs, t1, sizeof(t1));
@ -1366,14 +1368,13 @@ void test_nghttp2_hd_huff_encode(void) {
nghttp2_hd_huff_decode_context_init(&ctx); nghttp2_hd_huff_decode_context_init(&ctx);
len = nghttp2_hd_huff_decode(&ctx, &outbufs, bufs.cur->buf.pos, len = nghttp2_hd_huff_decode(&ctx, &outbuf, bufs.cur->buf.pos,
nghttp2_bufs_len(&bufs), 1); nghttp2_bufs_len(&bufs), 1);
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == len); CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == len);
CU_ASSERT((ssize_t)sizeof(t1) == nghttp2_bufs_len(&outbufs)); CU_ASSERT((ssize_t)sizeof(t1) == nghttp2_buf_len(&outbuf));
CU_ASSERT(0 == memcmp(t1, outbufs.cur->buf.pos, sizeof(t1))); CU_ASSERT(0 == memcmp(t1, outbuf.pos, sizeof(t1)));
nghttp2_bufs_free(&bufs); nghttp2_bufs_free(&bufs);
nghttp2_bufs_free(&outbufs);
} }