nghttp2_hd: Avoid nghttp2_hd_huff_decode_count

Huffman decoding is costly. It is faster to do geometric realloc
than calling nghttp2_hd_huff_decode_count to know the length in
advance.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-07 21:44:56 +09:00
parent ccd0f83018
commit 9eb031ce83
3 changed files with 40 additions and 36 deletions

View File

@ -1237,26 +1237,6 @@ static int inflater_post_process_hd_entry(nghttp2_hd_context *inflater,
return 0;
}
static ssize_t inflate_decode(uint8_t **dest_ptr, uint8_t *in, size_t inlen,
nghttp2_hd_side side)
{
ssize_t declen;
if(inlen == 0) {
*dest_ptr = NULL;
return 0;
}
declen = nghttp2_hd_huff_decode_count(in, inlen, side);
if(declen == -1) {
return NGHTTP2_ERR_HEADER_COMP;
}
*dest_ptr = malloc(declen);
if(*dest_ptr == NULL) {
return NGHTTP2_ERR_HEADER_COMP;
}
nghttp2_hd_huff_decode(*dest_ptr, declen, in, inlen, side);
return declen;
}
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
nghttp2_nv **nva_ptr,
uint8_t *in, size_t inlen)
@ -1341,7 +1321,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail;
}
if(name_huffman) {
rv = inflate_decode(&nv.name, in, namelen, inflater->side);
rv = nghttp2_hd_huff_decode(&nv.name, in, namelen, inflater->side);
if(rv < 0) {
DEBUGF(fprintf(stderr, "Name huffman decoding failed\n"));
goto fail;
@ -1369,7 +1349,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail;
}
if(value_huffman) {
rv = inflate_decode(&nv.value, in, valuelen, inflater->side);
rv = nghttp2_hd_huff_decode(&nv.value, in, valuelen, inflater->side);
if(rv < 0) {
DEBUGF(fprintf(stderr, "Value huffman decoding failed\n"));
free(decoded_huffman_name);
@ -1453,7 +1433,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail;
}
if(value_huffman) {
rv = inflate_decode(&value, in, valuelen, inflater->side);
rv = nghttp2_hd_huff_decode(&value, in, valuelen, inflater->side);
if(rv < 0) {
DEBUGF(fprintf(stderr, "Value huffman decoding failed\n"));
goto fail;

View File

@ -381,12 +381,11 @@ ssize_t nghttp2_hd_huff_decode_count(const uint8_t *src, size_t srclen,
nghttp2_hd_side side);
/*
* Decodes the given data |src| with length |srclen| to the given
* memory location pointed by |dest|, allocated at lest |destlen|
* bytes. The given input must be padded with the prefix of terminal
* code. The caller is responsible to specify |destlen| at least the
* length that nghttp2_hd_huff_decode_count() returns. If |side| is
* NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* Decodes the given data |src| with length |srclen|. This function
* allocates memory to store the result and assigns the its pointer to
* |*dest_ptr| on success. The caller is responsible to release the
* memory pointed by |*dest_ptr| if this function succeeds. If |side|
* is NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* used. Otherwise, the response code table is used.
*
* This function returns the number of written bytes. This return
@ -394,9 +393,15 @@ ssize_t nghttp2_hd_huff_decode_count(const uint8_t *src, size_t srclen,
* nghttp2_hd_huff_decode_count() if it is given with the same |src|,
* |srclen|, and |side|.
*
* This function returns -1 if it fails.
* If this function fails, it returns one of the following negative
* return codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_HEADER_COMP
* Decoding process has failed.
*/
ssize_t nghttp2_hd_huff_decode(uint8_t *dest, size_t destlen,
ssize_t nghttp2_hd_huff_decode(uint8_t **dest_ptr,
const uint8_t *src, size_t srclen,
nghttp2_hd_side side);

View File

@ -213,7 +213,7 @@ ssize_t nghttp2_hd_huff_decode_count(const uint8_t *src, size_t srclen,
return j;
}
ssize_t nghttp2_hd_huff_decode(uint8_t *dest, size_t destlen,
ssize_t nghttp2_hd_huff_decode(uint8_t **dest_ptr,
const uint8_t *src, size_t srclen,
nghttp2_hd_side side)
{
@ -221,6 +221,9 @@ ssize_t nghttp2_hd_huff_decode(uint8_t *dest, size_t destlen,
size_t i, j;
const nghttp2_huff_sym *huff_sym_table;
const huff_decode_table_type *huff_decode_table;
uint8_t *dest = NULL;
size_t destlen = 0;
int rv;
if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table;
@ -231,23 +234,39 @@ ssize_t nghttp2_hd_huff_decode(uint8_t *dest, size_t destlen,
}
j = 0;
for(i = 0; i < srclen;) {
int rv = huff_decode(src + i, srclen - i, bitoff,
huff_sym_table, huff_decode_table);
rv = huff_decode(src + i, srclen - i, bitoff,
huff_sym_table, huff_decode_table);
if(rv == -1) {
if(check_last_byte(src, srclen, i, bitoff)) {
break;
}
return -1;
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
if(rv == 256) {
/* 256 is special terminal symbol and it should not encoded in
byte string. */
return -1;
rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
}
if(j == destlen) {
size_t new_len = j == 0 ? 32 : j * 2;
uint8_t *new_dest = realloc(dest, new_len);
if(new_dest == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
}
dest = new_dest;
destlen = new_len;
}
dest[j++] = rv;
bitoff += huff_sym_table[rv].nbits;
i += bitoff / 8;
bitoff &= 0x7;
}
*dest_ptr = dest;
return j;
fail:
free(dest);
return rv;
}