Merge branch 'hpack-vec'

This commit is contained in:
Tatsuhiro Tsujikawa 2016-08-17 21:09:44 +09:00
commit e36caef006
6 changed files with 137 additions and 63 deletions

View File

@ -4603,14 +4603,15 @@ nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
* @function * @function
* *
* Deflates the |nva|, which has the |nvlen| name/value pairs, into * Deflates the |nva|, which has the |nvlen| name/value pairs, into
* the |inlen| size of buf vector |bufsin|, each buf has length |buflen|. * the |veclen| size of buf vector |vec|. The each size of buffer
* |buflens| is a |inlen| size of array, which will be used to store the writen * must be set in len field of :type:`nghttp2_vec`, and this function
* size of each chunk. If one chunk is filled up, next chunk will be used. * assumes all buffer size is equal. The application is responsible
* If |bufsin| is not large enough to store the deflated header block, * to make sure that this assumption holds. If one chunk is filled
* this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The * up, next chunk will be used. If |vec| is not large enough to store
* caller should use `nghttp2_hd_deflate_bound()` to know the upper * the deflated header block, this function fails with
* bound of buffer size required to deflate given header name/value * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller should use
* pairs. * `nghttp2_hd_deflate_bound()` to know the upper bound of buffer size
* required to deflate given header name/value pairs.
* *
* Once this function fails, subsequent call of this function always * Once this function fails, subsequent call of this function always
* returns :enum:`NGHTTP2_ERR_HEADER_COMP`. * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
@ -4626,11 +4627,12 @@ nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
* Deflation process has failed. * Deflation process has failed.
* :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output. * The provided |buflen| size is too small to hold the output.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The size of each buffer in |nva| is not the same.
*/ */
NGHTTP2_EXTERN ssize_t NGHTTP2_EXTERN ssize_t
nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, uint8_t *const *bufsin, nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, const nghttp2_vec *vec,
size_t inlen, size_t buflen, size_t *const buflens, size_t veclen, const nghttp2_nv *nva, size_t nvlen);
const nghttp2_nv *nva, size_t nvlen);
/** /**
* @function * @function

View File

@ -223,23 +223,26 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
return 0; return 0;
} }
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, uint8_t *const *bufs_in, int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
size_t in_len, size_t buf_len, nghttp2_mem *mem) { size_t veclen, size_t chunklen, nghttp2_mem *mem) {
size_t i = 0; size_t i = 0;
nghttp2_buf_chain *cur_chain; nghttp2_buf_chain *cur_chain;
nghttp2_buf_chain *head_chain; nghttp2_buf_chain *head_chain;
nghttp2_buf_chain **dst_chain = &head_chain; nghttp2_buf_chain **dst_chain = &head_chain;
head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * in_len); if (veclen == 0 || chunklen == 0) {
return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem);
}
head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen);
if (head_chain == NULL) { if (head_chain == NULL) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
for (i = 0; i < in_len; ++i) { for (i = 0; i < veclen; ++i) {
uint8_t *begin = bufs_in[i];
cur_chain = &head_chain[i]; cur_chain = &head_chain[i];
cur_chain->next = NULL; cur_chain->next = NULL;
nghttp2_buf_wrap_init(&cur_chain->buf, begin, buf_len); nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len);
*dst_chain = cur_chain; *dst_chain = cur_chain;
dst_chain = &cur_chain->next; dst_chain = &cur_chain->next;
@ -251,10 +254,10 @@ int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, uint8_t *const *bufs_in,
bufs->head = head_chain; bufs->head = head_chain;
bufs->cur = bufs->head; bufs->cur = bufs->head;
bufs->chunk_length = buf_len; bufs->chunk_length = chunklen;
bufs->chunk_used = in_len; bufs->chunk_used = veclen;
bufs->max_chunk = in_len; bufs->max_chunk = veclen;
bufs->chunk_keep = in_len; bufs->chunk_keep = veclen;
return 0; return 0;
} }
@ -266,7 +269,6 @@ void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
if (bufs->head) { if (bufs->head) {
nghttp2_mem_free(bufs->mem, bufs->head); nghttp2_mem_free(bufs->mem, bufs->head);
bufs->head = NULL;
} }
} }
@ -294,20 +296,6 @@ size_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
return len; return len;
} }
size_t nghttp2_bufs_len_vec(nghttp2_bufs *bufs, size_t *const buflens) {
nghttp2_buf_chain *ci;
size_t len, total_len = 0;
int i = 0;
for (ci = bufs->head; ci; ci = ci->next) {
len = nghttp2_buf_len(&ci->buf);
total_len += len;
buflens[i++] = len;
}
return total_len;
}
static size_t bufs_avail(nghttp2_bufs *bufs) { static size_t bufs_avail(nghttp2_bufs *bufs) {
return nghttp2_buf_avail(&bufs->cur->buf) + return nghttp2_buf_avail(&bufs->cur->buf) +
(bufs->chunk_length - bufs->offset) * (bufs->chunk_length - bufs->offset) *

View File

@ -211,11 +211,11 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_mem *mem); nghttp2_mem *mem);
/* /*
* Initializes |bufs| using supplied |in_len| size of buf vector |bufs_in|, * Initializes |bufs| using supplied |veclen| size of buf vector
* each buf has length |buf_len|. * |vec|, assuming that each buffer has length |chunklen|. The buffer
* The buffer size is fixed and no extra chunk buffer is allocated. * size is fixed and no extra chunk buffer is allocated. In other
* In other words, max_chunk = chunk_keep = |in_len|. To free the resource allocated * words, max_chunk = chunk_keep = |in_len|. To free the resource
* for |bufs|, use nghttp2_bufs_wrap_free(). * allocated for |bufs|, use nghttp2_bufs_wrap_free().
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -223,8 +223,8 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, uint8_t *const *bufs_in, int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
size_t in_len, size_t buf_len, nghttp2_mem *mem); size_t veclen, size_t chunklen, nghttp2_mem *mem);
/* /*
* Frees any related resource to the |bufs|. This function does not * Frees any related resource to the |bufs|. This function does not
@ -401,9 +401,4 @@ int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
*/ */
size_t nghttp2_bufs_len(nghttp2_bufs *bufs); size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
/*
* Returns the total buffer length of |bufs|, and each buffer length in |buflens|.
*/
size_t nghttp2_bufs_len_vec(nghttp2_bufs *bufs, size_t *const buflens);
#endif /* NGHTTP2_BUF_H */ #endif /* NGHTTP2_BUF_H */

View File

@ -1504,18 +1504,30 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
} }
ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
uint8_t *const *bufsin, size_t inlen, const nghttp2_vec *vec, size_t veclen,
size_t buflen, size_t *const buflens,
const nghttp2_nv *nv, size_t nvlen) { const nghttp2_nv *nv, size_t nvlen) {
nghttp2_bufs bufs; nghttp2_bufs bufs;
int rv; int rv;
nghttp2_mem *mem; nghttp2_mem *mem;
size_t i;
size_t buflen;
size_t chunklen;
memset(buflens, 0, sizeof(size_t) * inlen); if (veclen == 0) {
chunklen = 0;
} else {
for (i = 1; i < veclen; ++i) {
if (vec[0].len != vec[i].len) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
}
chunklen = vec[0].len;
}
mem = deflater->ctx.mem; mem = deflater->ctx.mem;
rv = nghttp2_bufs_wrap_init2(&bufs, bufsin, inlen, buflen, mem); rv = nghttp2_bufs_wrap_init2(&bufs, vec, veclen, chunklen, mem);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
@ -1523,7 +1535,7 @@ ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen);
buflen = nghttp2_bufs_len_vec(&bufs, buflens); buflen = nghttp2_bufs_len(&bufs);
nghttp2_bufs_wrap_free(&bufs); nghttp2_bufs_wrap_free(&bufs);

View File

@ -64,15 +64,44 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
code <<= 8 - (nbits & 0x7); code <<= 8 - (nbits & 0x7);
} }
/* we lose at most 3 bytes, but it is not critical in practice */
if (*avail_ptr < (nbits + 7) / 8) { if (*avail_ptr < (nbits + 7) / 8) {
rv = nghttp2_bufs_advance(bufs); /* slow path */
if (nbits > 24) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 24));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits > 16) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 16));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits > 8) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 8));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits == 8) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)code);
if (rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return 8;
}
rv = nghttp2_bufs_addb_hold(bufs, (uint8_t)code);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
*avail_ptr = nghttp2_bufs_cur_avail(bufs); *avail_ptr = nghttp2_bufs_cur_avail(bufs);
/* we assume that we at least 3 buffer space available */ return (ssize_t)(8 - nbits);
assert(*avail_ptr >= 3);
} }
/* fast path, since most code is less than 8 */ /* fast path, since most code is less than 8 */

View File

@ -1278,8 +1278,7 @@ void test_nghttp2_hd_deflate_hd_vec(void) {
uint8_t buf[4096]; uint8_t buf[4096];
ssize_t blocklen; ssize_t blocklen;
nghttp2_mem *mem; nghttp2_mem *mem;
uint8_t *bufsin[2]; nghttp2_vec vec[2];
size_t buflens[2] = {0};
size_t buflen; size_t buflen;
nghttp2_bufs bufs; nghttp2_bufs bufs;
nva_out out; nva_out out;
@ -1293,11 +1292,13 @@ void test_nghttp2_hd_deflate_hd_vec(void) {
buflen = nghttp2_hd_deflate_bound(deflater, nva, ARRLEN(nva)); buflen = nghttp2_hd_deflate_bound(deflater, nva, ARRLEN(nva));
bufsin[0] = &buf[0]; vec[0].base = &buf[0];
bufsin[1] = &buf[buflen / 2]; vec[0].len = buflen / 2;
vec[1].base = &buf[buflen / 2];
vec[1].len = buflen / 2;
blocklen = nghttp2_hd_deflate_hd_vec(deflater, bufsin, ARRLEN(bufsin), blocklen =
buflen / 2, buflens, nva, ARRLEN(nva)); nghttp2_hd_deflate_hd_vec(deflater, vec, ARRLEN(vec), nva, ARRLEN(nva));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
@ -1314,6 +1315,53 @@ void test_nghttp2_hd_deflate_hd_vec(void) {
nghttp2_hd_inflate_del(inflater); nghttp2_hd_inflate_del(inflater);
nghttp2_hd_deflate_del(deflater); nghttp2_hd_deflate_del(deflater);
nva_out_reset(&out, mem); nva_out_reset(&out, mem);
/* check the case when veclen is 0 */
nghttp2_hd_deflate_new(&deflater, 4096);
nghttp2_hd_inflate_new(&inflater);
blocklen = nghttp2_hd_deflate_hd_vec(deflater, NULL, 0, nva, ARRLEN(nva));
CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == blocklen);
nghttp2_hd_inflate_del(inflater);
nghttp2_hd_deflate_del(deflater);
/* check the case when chunk length is 0 */
vec[0].base = NULL;
vec[0].len = 0;
vec[1].base = NULL;
vec[1].len = 0;
nghttp2_hd_deflate_new(&deflater, 4096);
nghttp2_hd_inflate_new(&inflater);
blocklen =
nghttp2_hd_deflate_hd_vec(deflater, vec, ARRLEN(vec), nva, ARRLEN(nva));
CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == blocklen);
nghttp2_hd_inflate_del(inflater);
nghttp2_hd_deflate_del(deflater);
/* check the case where chunk size differs in each chunk */
nghttp2_hd_deflate_new(&deflater, 4096);
nghttp2_hd_inflate_new(&inflater);
buflen = nghttp2_hd_deflate_bound(deflater, nva, ARRLEN(nva));
vec[0].base = &buf[0];
vec[0].len = buflen / 2;
vec[1].base = &buf[buflen / 2];
vec[1].len = (buflen / 2) - 1;
blocklen =
nghttp2_hd_deflate_hd_vec(deflater, vec, ARRLEN(vec), nva, ARRLEN(nva));
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == blocklen);
nghttp2_hd_inflate_del(inflater);
nghttp2_hd_deflate_del(deflater);
} }
static size_t encode_length(uint8_t *buf, uint64_t n, size_t prefix) { static size_t encode_length(uint8_t *buf, uint64_t n, size_t prefix) {