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; 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, 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)
@ -1341,7 +1321,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
if(name_huffman) { 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) { if(rv < 0) {
DEBUGF(fprintf(stderr, "Name huffman decoding failed\n")); DEBUGF(fprintf(stderr, "Name huffman decoding failed\n"));
goto fail; goto fail;
@ -1369,7 +1349,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
if(value_huffman) { 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) { if(rv < 0) {
DEBUGF(fprintf(stderr, "Value huffman decoding failed\n")); DEBUGF(fprintf(stderr, "Value huffman decoding failed\n"));
free(decoded_huffman_name); free(decoded_huffman_name);
@ -1453,7 +1433,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
goto fail; goto fail;
} }
if(value_huffman) { if(value_huffman) {
rv = inflate_decode(&value, in, valuelen, inflater->side); rv = nghttp2_hd_huff_decode(&value, in, valuelen, inflater->side);
if(rv < 0) { if(rv < 0) {
DEBUGF(fprintf(stderr, "Value huffman decoding failed\n")); DEBUGF(fprintf(stderr, "Value huffman decoding failed\n"));
goto fail; 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); nghttp2_hd_side side);
/* /*
* Decodes the given data |src| with length |srclen| to the given * Decodes the given data |src| with length |srclen|. This function
* memory location pointed by |dest|, allocated at lest |destlen| * allocates memory to store the result and assigns the its pointer to
* bytes. The given input must be padded with the prefix of terminal * |*dest_ptr| on success. The caller is responsible to release the
* code. The caller is responsible to specify |destlen| at least the * memory pointed by |*dest_ptr| if this function succeeds. If |side|
* length that nghttp2_hd_huff_decode_count() returns. If |side| is * is NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is
* used. Otherwise, the response code table is used. * used. Otherwise, the response code table is used.
* *
* This function returns the number of written bytes. This return * 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|, * nghttp2_hd_huff_decode_count() if it is given with the same |src|,
* |srclen|, and |side|. * |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, const uint8_t *src, size_t srclen,
nghttp2_hd_side side); 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; 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, const uint8_t *src, size_t srclen,
nghttp2_hd_side side) nghttp2_hd_side side)
{ {
@ -221,6 +221,9 @@ ssize_t nghttp2_hd_huff_decode(uint8_t *dest, size_t destlen,
size_t i, j; size_t i, j;
const nghttp2_huff_sym *huff_sym_table; const nghttp2_huff_sym *huff_sym_table;
const huff_decode_table_type *huff_decode_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) { if(side == NGHTTP2_HD_SIDE_REQUEST) {
huff_sym_table = req_huff_sym_table; 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; j = 0;
for(i = 0; i < srclen;) { for(i = 0; i < srclen;) {
int rv = huff_decode(src + i, srclen - i, bitoff, rv = huff_decode(src + i, srclen - i, bitoff,
huff_sym_table, huff_decode_table); huff_sym_table, huff_decode_table);
if(rv == -1) { if(rv == -1) {
if(check_last_byte(src, srclen, i, bitoff)) { if(check_last_byte(src, srclen, i, bitoff)) {
break; break;
} }
return -1; rv = NGHTTP2_ERR_HEADER_COMP;
goto fail;
} }
if(rv == 256) { if(rv == 256) {
/* 256 is special terminal symbol and it should not encoded in /* 256 is special terminal symbol and it should not encoded in
byte string. */ 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; dest[j++] = rv;
bitoff += huff_sym_table[rv].nbits; bitoff += huff_sym_table[rv].nbits;
i += bitoff / 8; i += bitoff / 8;
bitoff &= 0x7; bitoff &= 0x7;
} }
*dest_ptr = dest;
return j; return j;
fail:
free(dest);
return rv;
} }