Rework outbound frame buffers

This commit is contained in:
Tatsuhiro Tsujikawa 2014-03-13 22:11:02 +09:00
parent 0666a73e10
commit d07bb1ddff
18 changed files with 1532 additions and 1062 deletions

View File

@ -123,11 +123,17 @@ static void nghttp2_buf_chain_del(nghttp2_buf_chain *chain)
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk)
{
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0);
}
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset)
{
int rv;
nghttp2_buf_chain *chain;
if(max_chunk == 0) {
if(max_chunk == 0 || chunk_length < offset) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@ -136,9 +142,13 @@ int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
return rv;
}
bufs->offset = offset;
bufs->head = chain;
bufs->cur = bufs->head;
nghttp2_buf_shift_right(&bufs->cur->buf, offset);
bufs->chunk_length = chunk_length;
bufs->chunk_left = max_chunk - 1;
@ -158,10 +168,36 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs)
}
}
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
{
nghttp2_buf_chain *ci;
for(ci = bufs->cur; ci->next; ci = ci->next) {
if(nghttp2_buf_len(&ci->buf) == 0) {
return;
} else {
bufs->cur = ci;
}
}
}
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs)
{
nghttp2_buf_chain *ci;
ssize_t len;
len = 0;
for(ci = bufs->head; ci; ci = ci->next) {
len += nghttp2_buf_len(&ci->buf);
}
return len;
}
static int nghttp2_bufs_avail(nghttp2_bufs *bufs)
{
return nghttp2_buf_avail(&bufs->cur->buf) +
bufs->chunk_left * bufs->chunk_left;
(bufs->chunk_left - bufs->offset) * bufs->chunk_left;
}
static int nghttp2_bufs_alloc_chain(nghttp2_bufs *bufs)
@ -189,6 +225,8 @@ static int nghttp2_bufs_alloc_chain(nghttp2_bufs *bufs)
bufs->cur->next = chain;
bufs->cur = chain;
nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
return 0;
}
@ -199,7 +237,7 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
nghttp2_buf *buf;
const uint8_t *p;
if((size_t)nghttp2_bufs_avail(bufs) < len) {
if(nghttp2_bufs_avail(bufs) < (ssize_t)len) {
return NGHTTP2_ERR_BUFFER_ERROR;
}
@ -224,7 +262,7 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
return 0;
}
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
static int nghttp2_bufs_ensure_addb(nghttp2_bufs *bufs)
{
int rv;
nghttp2_buf *buf;
@ -232,7 +270,6 @@ int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
buf = &bufs->cur->buf;
if(nghttp2_buf_avail(buf) > 0) {
*buf->last++ = b;
return 0;
}
@ -241,9 +278,61 @@ int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
return rv;
}
buf = &bufs->cur->buf;
return 0;
}
*buf->last++ = b;
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
{
int rv;
rv = nghttp2_bufs_ensure_addb(bufs);
if(rv != 0) {
return rv;
}
*bufs->cur->buf.last++ = b;
return 0;
}
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
{
int rv;
rv = nghttp2_bufs_ensure_addb(bufs);
if(rv != 0) {
return rv;
}
*bufs->cur->buf.last = b;
return 0;
}
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
{
int rv;
rv = nghttp2_bufs_ensure_addb(bufs);
if(rv != 0) {
return rv;
}
*bufs->cur->buf.last++ |= b;
return 0;
}
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
{
int rv;
rv = nghttp2_bufs_ensure_addb(bufs);
if(rv != 0) {
return rv;
}
*bufs->cur->buf.last |= b;
return 0;
}
@ -272,7 +361,9 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
for(chain = bufs->head; chain; chain = chain->next) {
buf = &chain->buf;
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
nghttp2_buf_reset(buf);
nghttp2_buf_shift_right(&chain->buf, bufs->offset);
}
bufs->cur = bufs->head;
@ -288,5 +379,23 @@ void nghttp2_bufs_reset(nghttp2_bufs *bufs)
for(chain = bufs->head; chain; chain = chain->next) {
nghttp2_buf_reset(&chain->buf);
nghttp2_buf_shift_right(&chain->buf, bufs->offset);
}
bufs->cur = bufs->head;
}
int nghttp2_bufs_advance(nghttp2_bufs *bufs)
{
return nghttp2_bufs_alloc_chain(bufs);
}
int nghttp2_bufs_next_present(nghttp2_bufs *bufs)
{
nghttp2_buf_chain *chain;
chain = bufs->cur->next;
return chain && nghttp2_buf_len(&chain->buf);
}

View File

@ -134,39 +134,202 @@ void nghttp2_buf_reset(nghttp2_buf *buf);
*/
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
/*
* List of nghttp2_buf
*/
struct nghttp2_buf_chain;
typedef struct nghttp2_buf_chain nghttp2_buf_chain;
/* Chains 2 buffers */
struct nghttp2_buf_chain {
/* Points to the subsequent buffer. NULL if there is no such
buffer. */
nghttp2_buf_chain *next;
nghttp2_buf buf;
};
typedef struct {
/* Points to the first buffer */
nghttp2_buf_chain *head;
/* Buffer pointer where write occurs. */
nghttp2_buf_chain *cur;
/* The buffer capacity of each buf */
size_t chunk_length;
/* The maximum number of nghttp2_buf_chain */
size_t chunk_left;
/* pos offset from begin in each buffers. On initialization and
reset, buf->pos and buf->last are positioned at buf->begin +
offset. */
size_t offset;
} nghttp2_bufs;
/*
* This is the same as calling nghttp2_bufs_init2 with the given
* arguments and offset = 0.
*/
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk);
/*
* Initializes |bufs|. Each buffer size is given in the
* |chunk_length|. The maximum number of buffers is given in the
* |max_chunk|. Each buffer will have bufs->pos and bufs->last shifted
* to left by |offset| bytes on creation and reset.
*
* This function allocates first buffer. bufs->head and bufs->cur
* will point to the first buffer after this call.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* max_chunk is 0
*/
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset);
/*
* Frees any related resources to the |bufs|.
*/
void nghttp2_bufs_free(nghttp2_bufs *bufs);
/*
* Appends the |data| of length |len| to the |bufs|. The write starts
* at bufs->cur->buf.last. A new buffers will be allocated to store
* all data.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);
/*
* Appends a single byte |b| to the |bufs|. The write starts at
* bufs->cur->buf.last. A new buffers will be allocated to store all
* data.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
/*
* Behaves like nghttp2_bufs_addb(), but this does not update
* buf->last pointer.
*/
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_addb(BUFS, B) \
do { \
*(BUFS)->cur->buf.last++ = B; \
} while(0)
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
do { \
*(BUFS)->cur->buf.last = B; \
} while(0)
/*
* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
* will be allocated if necessary.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
/*
* Behaves like nghttp2_bufs_orb(), but does not update buf->last
* pointer.
*/
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_orb(BUFS, B) \
do { \
*(BUFS)->cur->buf.last++ |= B; \
} while(0)
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
do { \
*(BUFS)->cur->buf.last |= B; \
} while(0)
/*
* Copies all data stored in |bufs| to the contagious buffer. This
* function allocates the contagious memory to store all data in
* |bufs| and assigns it to |*out|.
*
* On successful return, nghttp2_bufs_len(bufs) returns 0, just like
* after calling nghttp2_bufs_reset().
* This function returns the length of copied data and assigns the
* pointer to copied data to |*out| if it succeeds, or one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
/*
* Resets |bufs| and makes the buffers empty.
*/
void nghttp2_bufs_reset(nghttp2_bufs *bufs);
/*
* Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is
* NULL, this function allocates new buffers and bufs->cur points to
* it.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_advance(nghttp2_bufs *bufs);
/* Sets bufs->cur to bufs->head */
#define nghttp2_bufs_rewind(BUFS) \
do { \
(BUFS)->cur = (BUFS)->head; \
} while(0)
/*
* Move bufs->cur, from the current position, using next member, to
* the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf
* which satisfies nghttp2_buf_len(buf) == 0. If bufs->cur->next is
* NULL, bufs->cur is unchanged.
*/
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
/*
* Returns nonzero if bufs->cur->next is not emtpy.
*/
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
/*
* Returns the buffer length of |bufs|.
*/
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs);
#endif /* NGHTTP2_BUF_H */

View File

@ -224,64 +224,109 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
}
}
ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater)
/*
* Call this function after payload was serialized, but not before
* changing buf->pos and serializing frame header.
*
* This function assumes bufs->cur points to the last buf chain of the
* frame(s).
*
* This function serializes frame header for HEADERS/PUSH_PROMISE and
* handles their successive CONTINUATION frames.
*
* We don't process any padding here.
*/
static int frame_pack_headers_shared(nghttp2_bufs *bufs,
nghttp2_frame_hd *frame_hd)
{
nghttp2_buf *buf;
nghttp2_buf_chain *ci, *ce;
nghttp2_frame_hd hd;
buf = &bufs->head->buf;
hd = *frame_hd;
hd.length = nghttp2_buf_len(buf);
DEBUGF(fprintf(stderr, "HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length));
/* We have multiple frame buffers, which means one or more
CONTINUATION frame is involved. Remove END_HEADERS flag from the
first frame. */
if(bufs->head != bufs->cur) {
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
}
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
if(bufs->head != bufs->cur) {
/* 2nd and later frames are CONTINUATION frames. */
hd.type = NGHTTP2_CONTINUATION;
/* We don't have no flags except for last CONTINUATION */
hd.flags = NGHTTP2_FLAG_NONE;
ce = bufs->cur;
for(ci = bufs->head->next; ci != ce; ci = ci->next) {
buf = &ci->buf;
hd.length = nghttp2_buf_len(buf);
DEBUGF(fprintf(stderr, "int CONTINUATION, payloadlen=%zu\n", hd.length));
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
}
buf = &ci->buf;
hd.length = nghttp2_buf_len(buf);
/* Set END_HEADERS flag for last CONTINUATION */
hd.flags = NGHTTP2_FLAG_END_HEADERS;
DEBUGF(fprintf(stderr, "last CONTINUATION, payloadlen=%zu\n", hd.length));
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
}
return 0;
}
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater)
{
size_t nv_offset;
ssize_t rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
/* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
nv_offset = nghttp2_frame_headers_payload_nv_offset(frame);
nv_offset =
NGHTTP2_FRAME_HDLEN + nghttp2_frame_headers_payload_nv_offset(frame);
/* If frame->nvlen == 0, nghttp2_buf_len(buf) may be smaller than
nv_offset */
rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) {
return rv;
}
buf = &bufs->cur->buf;
buf->pos += nv_offset;
buf->last = buf->pos;
/* This call will adjust buf->last to the correct position */
rv = nghttp2_hd_deflate_hd(deflater, buf, frame->nva, frame->nvlen);
rv = nghttp2_hd_deflate_hd(deflater, bufs, frame->nva, frame->nvlen);
buf->pos -= nv_offset;
if(rv < 0) {
if(rv != 0) {
return rv;
}
frame->hd.length = nghttp2_frame_headers_payload_nv_offset(frame) + rv;
frame->padlen = 0;
/* Don't use buf->last, since it already points to the end of the
frame */
memset(buf->pos, 0, NGHTTP2_FRAME_HDLEN);
/* pack frame header after length is determined */
if(NGHTTP2_MAX_PAYLOADLEN < frame->hd.length) {
/* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_PAYLOADLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else {
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
}
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN, frame->pri);
nghttp2_put_uint32be(buf->pos, frame->pri);
}
return nghttp2_buf_len(buf);
frame->padlen = 0;
frame->hd.length = nghttp2_bufs_len(bufs);
return frame_pack_headers_shared(bufs, &frame->hd);
}
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
@ -298,28 +343,21 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
return 0;
}
ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame)
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
{
ssize_t framelen= NGHTTP2_FRAME_HDLEN + 4;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
buf = &bufs->head->buf;
buf->pos -= NGHTTP2_FRAME_HDLEN;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
nghttp2_put_uint32be(buf->last, frame->pri);
buf->last += 4;
return nghttp2_buf_len(buf);
return 0;
}
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
@ -329,28 +367,22 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
}
ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame)
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
nghttp2_rst_stream *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HDLEN + 4;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
buf = &bufs->head->buf;
buf->pos -= NGHTTP2_FRAME_HDLEN;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
return nghttp2_buf_len(buf);
return 0;
}
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
@ -360,28 +392,26 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
frame->error_code = nghttp2_get_uint32(payload);
}
ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame)
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HDLEN + frame->hd.length;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
buf = &bufs->head->buf;
if(nghttp2_buf_avail(buf) < (ssize_t)frame->hd.length) {
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
}
memset(buf->last, 0, framelen);
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
buf->last += nghttp2_frame_pack_settings_payload(buf->last,
frame->iv, frame->niv);
return nghttp2_buf_len(buf);
return 0;
}
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
@ -436,60 +466,36 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
return 0;
}
ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater)
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater)
{
size_t nv_offset = NGHTTP2_FRAME_HDLEN + 4;
size_t nv_offset = 4;
ssize_t rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
/* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
/* If frame->nvlen == 0, nghttp2_buf_len(buf) may be smaller than
nv_offset */
rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) {
return rv;
}
buf = &bufs->cur->buf;
buf->pos += nv_offset;
buf->last = buf->pos;
/* This call will adjust buf->last to the correct position */
rv = nghttp2_hd_deflate_hd(deflater, buf, frame->nva, frame->nvlen);
rv = nghttp2_hd_deflate_hd(deflater, bufs, frame->nva, frame->nvlen);
buf->pos -= nv_offset;
if(rv < 0) {
if(rv != 0) {
return rv;
}
frame->hd.length = 4 + rv;
nghttp2_put_uint32be(buf->pos, frame->promised_stream_id);
frame->padlen = 0;
frame->hd.length = nghttp2_bufs_len(bufs);
/* Don't use buf->last, since it already points to the end of the
frame */
memset(buf->pos, 0, NGHTTP2_FRAME_HDLEN);
/* pack frame header after length is determined */
if(NGHTTP2_MAX_PAYLOADLEN < frame->hd.length) {
/* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_PAYLOADLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else {
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
}
nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN,
frame->promised_stream_id);
return nghttp2_buf_len(buf);
return frame_pack_headers_shared(bufs, &frame->hd);
}
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
@ -503,27 +509,21 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
return 0;
}
ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame)
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HDLEN + 8;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
buf = &bufs->head->buf;
buf->pos -= NGHTTP2_FRAME_HDLEN;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
buf->last = nghttp2_cpymem(buf->last, frame->opaque_data,
sizeof(frame->opaque_data));
memcpy(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
buf->last += sizeof(frame->opaque_data);
return nghttp2_buf_len(buf);
return 0;
}
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
@ -533,22 +533,18 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
}
ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame)
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HDLEN + frame->hd.length;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
buf = &bufs->head->buf;
memset(buf->last, 0, framelen);
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
nghttp2_put_uint32be(buf->last, frame->last_stream_id);
buf->last += 4;
@ -556,10 +552,12 @@ ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame)
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
memcpy(buf->last, frame->opaque_data, frame->opaque_data_len);
buf->last += frame->opaque_data_len;
rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len);
if(rv != 0) {
return rv;
}
return nghttp2_buf_len(buf);
return 0;
}
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
@ -573,28 +571,22 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
frame->opaque_data_len = 0;
}
ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame)
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
nghttp2_window_update *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HDLEN + 4;
int rv;
nghttp2_buf *buf;
assert(nghttp2_buf_len(buf) == 0);
assert(bufs->head == bufs->cur);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
buf = &bufs->head->buf;
buf->pos -= NGHTTP2_FRAME_HDLEN;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
nghttp2_put_uint32be(buf->last, frame->window_size_increment);
buf->last += 4;
return nghttp2_buf_len(buf);
return 0;
}
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
@ -737,34 +729,158 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
return 1;
}
void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr, size_t padlen)
static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
{
size_t trail_padlen = 0;
size_t trail_padlen;
if(padlen > 256) {
uint8_t *p;
DEBUGF(fprintf(stderr, "padlen=%zu, shift left 2 bytes\n", padlen));
memmove(buf->pos - 2, buf->pos, NGHTTP2_FRAME_HDLEN);
buf->pos -= 2;
buf->pos[3] |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
nghttp2_put_uint16be(buf->pos, nghttp2_get_uint16(buf->pos) + padlen);
trail_padlen = padlen - 2;
*flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
assert(nghttp2_buf_pos_offset(buf) >= 2);
/* Consume previous 2 bytes, shifting 2 bytes to the left */
nghttp2_buf_shift_left(buf, 2);
p = buf->pos + NGHTTP2_FRAME_HDLEN;
*p++ = trail_padlen >> 8;
*p = trail_padlen & 0xff;
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen >> 8;
buf->pos[NGHTTP2_FRAME_HDLEN + 1] = trail_padlen & 0xff;
} else if(padlen > 0) {
assert(nghttp2_buf_pos_offset(buf) >= 1);
DEBUGF(fprintf(stderr, "padlen=%zu, shift left 1 bytes\n", padlen));
/* Consume previous 1 byte, shifting 1 bytes to the left */
nghttp2_buf_shift_left(buf, 1);
memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN);
--buf->pos;
buf->pos[3] |= NGHTTP2_FLAG_PAD_LOW;
nghttp2_put_uint16be(buf->pos, nghttp2_get_uint16(buf->pos) + padlen);
trail_padlen = padlen - 1;
*flags_ptr |= NGHTTP2_FLAG_PAD_LOW;
buf->pos[NGHTTP2_FRAME_HDLEN] = trail_padlen;
*(buf->pos + NGHTTP2_FRAME_HDLEN) = trail_padlen;
} else {
DEBUGF(fprintf(stderr, "padlen=0, no shift left was made\n"));
return;
}
/* zero out padding */
memset(buf->last, 0, trail_padlen);
/* extend buffers trail_padlen bytes, since we ate previous padlen -
trail_padlen byte(s) */
buf->last += trail_padlen;
return;
}
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
size_t padlen, nghttp2_frame_type type)
{
int rv;
size_t trail_padlen;
size_t last_avail;
nghttp2_buf *buf;
nghttp2_frame_hd last_hd;
if(padlen == 0) {
DEBUGF(fprintf(stderr, "padlen = 0, nothing to do\n"));
return 0;
}
/*
* We have arranged bufs like this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | |Frame header | Frame payload... |
* +-+-+---------------+-------------------------------------------+
* | | |Frame header | Frame payload... |
* +-+-+---------------+-------------------------------------------+
* | | |Frame header | Frame payload... |
* +-+-+---------------+-------------------------------------------+
*
* Since we limit the length of the padding bytes, they are
* completely included in one frame payload or across 2 frames. We
* are going to adjust buf->pos of frame which includes part of
* padding. And serialize (memmove) frame header in the correct
* position. Also extends buf->last to include padding.
*/
nghttp2_bufs_seek_last_present(bufs);
buf = &bufs->cur->buf;
last_avail = nghttp2_buf_avail(buf);
if(last_avail >= padlen) {
/* Last frame can include all paddings bytes */
DEBUGF(fprintf(stderr, "last frame includes all paddings\n"));
frame_set_pad(buf, padlen);
} else {
/* padding across 2 frames */
/* type = DATA must not be here */
assert(type == NGHTTP2_CONTINUATION);
/* This will seek to the last chain */
rv = nghttp2_bufs_advance(bufs);
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
}
if(rv != 0) {
return rv;
}
if(type == NGHTTP2_CONTINUATION) {
/* former last frame has END_HEADERS flag set. Clear it. */
buf->pos[3] &= ~NGHTTP2_FLAG_END_HEADERS;
}
trail_padlen = nghttp2_buf_avail(buf);
/* former last frame may have zero buffer available */
if(trail_padlen == 0) {
DEBUGF(fprintf(stderr, "last frame has no space to include padding\n"));
} else {
DEBUGF(fprintf(stderr, "padding across 2 frames\n"));
frame_set_pad(buf, trail_padlen);
}
/* This buffer does not have frame header serialized */
buf = &bufs->cur->buf;
trail_padlen = padlen - trail_padlen;
last_hd.length = 0;
last_hd.type = type;
last_hd.stream_id = hd->stream_id;
if(type == NGHTTP2_CONTINUATION) {
last_hd.flags = NGHTTP2_FLAG_END_HEADERS;
} else {
last_hd.flags = NGHTTP2_FLAG_NONE;
}
buf->pos -= NGHTTP2_FRAME_HDLEN;
nghttp2_frame_pack_frame_hd(buf->pos, &last_hd);
frame_set_pad(buf, trail_padlen);
}
hd->length += padlen;
DEBUGF(fprintf(stderr, "final payloadlen=%zu, padlen=%zu\n",
hd->length, padlen));
return 0;
}

View File

@ -39,17 +39,21 @@
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The maximum payload length of a frame TODO: Must be renamed as
NGHTTP2_MAX_PAYLOAD_LENGTH */
#define NGHTTP2_MAX_PAYLOADLEN ((1 << 14) - 1)
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HDLEN 8
/* The maximum frame and payload length. The spec allows maximum
payload length up to 16383 bytes. Due to efficient buffer
allocation, we choose smaller buffer. Actual payload limit offsets
frame header and possible PAD_HIGH and PAD_LOW to ease
serialization and save memcopying. */
#define NGHTTP2_MAX_FRAMELEN 8192
#define NGHTTP2_MAX_PAYLOADLEN (NGHTTP2_MAX_FRAMELEN - NGHTTP2_FRAME_HDLEN - 2)
/* The maximum length of DATA frame payload. To fit entire DATA frame
into 4096K buffer, we use subtract header size (8 bytes) + 2 bytes
padding. See nghttp2_session_pack_data(). */
#define NGHTTP2_DATA_PAYLOAD_LENGTH 4086
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HDLEN 8
#define NGHTTP2_DATA_PAYLOAD_LENGTH (4096 - NGHTTP2_FRAME_HDLEN - 2)
/* The number of bytes for each SETTINGS entry */
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5
@ -101,33 +105,29 @@ void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
/*
* Packs HEADERS frame |frame| in wire format and store it in |buf|.
* This function expands |buf| as necessary to store frame. The caller
* must make sure that nghttp2_buf_len(buf) == 0 holds when calling
* this function.
* Packs HEADERS frame |frame| in wire format and store it in |bufs|.
* This function expands |bufs| as necessary to store frame.
*
* The first byte the frame is serialized is returned in the |buf|.
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
* NGHTTP2_MAX_PAYLOADLEN, payload data is still serialized as is, but
* serialized header's payload length is set to NGHTTP2_MAX_PAYLOADLEN
* and NGHTTP2_FLAG_END_HEADERS flag is cleared.
* packing process. CONTINUATION frames are also serialized in this
* function. This function does not handle padding.
*
* This function returns the size of packed frame (which equals to
* nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
* NGHTTP2_ERR_FRAME_TOO_LARGE
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
/*
* Unpacks HEADERS frame byte sequence into |frame|. This function
@ -145,8 +145,10 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
/*
* Packs PRIORITY frame |frame| in wire format and store it in
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
@ -154,8 +156,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame);
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs,
nghttp2_priority *frame);
/*
* Unpacks PRIORITY wire format into |frame|.
@ -166,17 +168,19 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
/*
* Packs RST_STREAM frame |frame| in wire frame format and store it in
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
* |bufs|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame);
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
nghttp2_rst_stream *frame);
/*
* Unpacks RST_STREAM frame byte sequence into |frame|.
@ -187,17 +191,20 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
/*
* Packs SETTINGS frame |frame| in wire format and store it in
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
* |bufs|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame);
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
/*
* Packs the |iv|, which includes |niv| entries, in the |buf|,
@ -245,32 +252,29 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
/*
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
* |buf|. This function expands |buf| as necessary to store
* frame. The caller must make sure that nghttp2_buf_len(buf) == 0
* holds when calling this function.
* |bufs|. This function expands |bufs| as necessary to store
* frame.
*
* The first byte the frame is serialized is returned in the |buf|.
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
* NGHTTP2_MAX_PAYLOADLEN, payload data is still serialized as is, but
* serialized header's payload length is set to NGHTTP2_MAX_PAYLOADLEN
* and NGHTTP2_FLAG_END_HEADERS flag is cleared.
* packing process. CONTINUATION frames are also serialized in this
* function. This function does not handle padding.
*
* This function returns the size of packed frame (which equals to
* nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
* NGHTTP2_ERR_FRAME_TOO_LARGE
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater);
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater);
/*
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This function
@ -287,8 +291,11 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
size_t payloadlen);
/*
* Packs PING frame |frame| in wire format and store it in |buf|. This
* function expands |buf| as necessary to store given |frame|.
* Packs PING frame |frame| in wire format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
@ -296,7 +303,7 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame);
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
/*
* Unpacks PING wire format into |frame|.
@ -306,17 +313,21 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
size_t payloadlen);
/*
* Packs GOAWAY frame |frame | in wire format and store it in
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
* This function expands |bufs| as necessary to store frame.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame);
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
/*
* Unpacks GOAWAY wire format into |frame|.
@ -327,17 +338,19 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
/*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |buf|. This function expands |buf| as necessary to store given
* |frame|.
* in |bufs|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame);
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
nghttp2_window_update *frame);
/*
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
@ -486,66 +499,21 @@ void nghttp2_nv_array_del(nghttp2_nv *nva);
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
/*
* Sets PAD_HIGH and PAD_LOW fields, flags and adjust buf->pos and
* buf->last accordingly based on given padding length. The padding is
* given in the |padlen|.
* Sets PAD_HIGH and PAD_LOW fields, flags and adjust frame header
* position of each buffers in |bufs|. The padding is given in the
* |padlen|. The |hd| is the frame header for the serialized data.
* The |type| is used as a frame type when padding requires additional
* buffers.
*
* The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and
* NGHTTP2_FLAG_PAD_HIGH based on the padding length.
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* This function does not allocate memory at all.
*
* The padding specifier PAD_HIGH and PAD_LOW are located right after
* the frame header. But they may not be there depending of the length
* of the padding. To save the additional buffer copy, we shift
* buf->pos to 2 bytes right before this call. Depending of the length
* of the padding, we shift left buf->pos and buf->last. If more than
* or equal to 256 padding is made, 2 left shift is done |buf| looks
* like this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Frame header ...
* +---------------------------------------------------------------+
* . Frame header |
* +---------------+---------------+-------------------------------+
* | Pad high | Pad low | Payload ...
* +---------------+---------------+-------------------------------+
*
*
* If padding is less than 256 but strictly more than 0, the |buf| is
* 1 left shift and the |buf| looks like this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Unused | Frame header ...
* +---------------+-----------------------------------------------+
* . Frame header ...
* +---------------+---------------+-------------------------------+
* . Frame Header | Pad low | Payload ...
* +---------------+---------------+-------------------------------+
*
* If no padding is added, no shift is done and the |buf| looks like
* this:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Unused | Frame header ...
* +-------------------------------+-------------------------------+
* . Frame header ...
* +-------------------------------+-------------------------------+
* . Frame Header | Payload ...
* +-------------------------------+-------------------------------+
*
* Notice that the position of payload does not change. This way, we
* can set PAD_HIGH and PAD_LOW after payload was serialized and no
* additional copy operation is required (if the |buf| is large enough
* to account the additional padding, of course).
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space. This is not a fatal.
*/
void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr,
size_t padlen);
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
size_t padlen, nghttp2_frame_type type);
#endif /* NGHTTP2_FRAME_H */

View File

@ -421,24 +421,6 @@ static int emit_literal_header(nghttp2_nv *nv_out, nghttp2_nv *nv)
return 0;
}
static int ensure_write_buffer(nghttp2_buf *buf, size_t need)
{
int rv;
need += nghttp2_buf_last_offset(buf);
if(need > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
return NGHTTP2_ERR_HEADER_COMP;
}
rv = nghttp2_buf_reserve(buf, need);
if(rv != 0) {
return NGHTTP2_ERR_NOMEM;
}
return 0;
}
static size_t count_encoded_length(size_t n, int prefix)
{
size_t k = (1 << prefix) - 1;
@ -545,90 +527,116 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
return in + 1;
}
static int emit_clear_refset(nghttp2_buf *buf)
static int nghttp2_hd_handle_buffer_error(int rv)
{
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
return NGHTTP2_ERR_HEADER_COMP;
}
return rv;
}
static int emit_clear_refset(nghttp2_bufs *bufs)
{
int rv;
uint8_t *bufp;
uint8_t sb[] = {0x80u, 0x80u};
rv = ensure_write_buffer(buf, 2);
rv = nghttp2_bufs_add(bufs, sb, sizeof(sb));
if(rv != 0) {
return rv;
return nghttp2_hd_handle_buffer_error(rv);
}
bufp = buf->last;
*bufp++ = 0x80u;
*bufp++ = 0x80u;
buf->last = bufp;
return 0;
}
static int emit_table_size(nghttp2_buf *buf, size_t table_size)
static int emit_table_size(nghttp2_bufs *bufs, size_t table_size)
{
int rv;
uint8_t *bufp;
size_t blocklen;
uint8_t sb[16];
blocklen = 1 + count_encoded_length(table_size, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
if(sizeof(sb) < blocklen) {
return NGHTTP2_ERR_HEADER_COMP;
}
DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size));
bufp = buf->last;
bufp = sb;
*bufp++ = 0x80u;
*bufp = 0;
encode_length(bufp, table_size, 7);
buf->last += blocklen;
rv = nghttp2_bufs_add(bufs, sb, blocklen);
if(rv != 0) {
return nghttp2_hd_handle_buffer_error(rv);
}
return 0;
}
static int emit_indexed_block(nghttp2_buf *buf, size_t index)
static int emit_indexed_block(nghttp2_bufs *bufs, size_t index)
{
int rv;
size_t blocklen;
uint8_t sb[16];
uint8_t *bufp;
blocklen = count_encoded_length(index + 1, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
if(sizeof(sb) < blocklen) {
return NGHTTP2_ERR_HEADER_COMP;
}
*buf->last = 0x80u;
encode_length(buf->last, index + 1, 7);
bufp = sb;
*bufp = 0x80u;
encode_length(bufp, index + 1, 7);
buf->last += blocklen;
rv = nghttp2_bufs_add(bufs, sb, blocklen);
if(rv != 0) {
return nghttp2_hd_handle_buffer_error(rv);
}
return 0;
}
static size_t emit_string(uint8_t *buf, size_t buflen,
size_t enclen, int huffman,
const uint8_t *str, size_t len)
static int emit_string(nghttp2_bufs *bufs,
size_t enclen, int huffman,
const uint8_t *str, size_t len)
{
size_t rv;
uint8_t sb[16];
uint8_t *bufp;
size_t blocklen;
blocklen = count_encoded_length(enclen, 7);
if(sizeof(sb) < blocklen) {
return NGHTTP2_ERR_HEADER_COMP;
}
bufp = sb;
*bufp = huffman ? 1 << 7 : 0;
rv = encode_length(bufp, enclen, 7);
rv = nghttp2_bufs_add(bufs, sb, blocklen);
if(rv != 0) {
return nghttp2_hd_handle_buffer_error(rv);
}
*buf = huffman ? 1 << 7 : 0;
rv = encode_length(buf, enclen, 7);
buf += rv;
if(huffman) {
nghttp2_hd_huff_encode(buf, buflen - rv, str, len);
rv = nghttp2_hd_huff_encode(bufs, str, len);
} else {
assert(enclen == len);
memcpy(buf, str, len);
rv = nghttp2_bufs_add(bufs, str, len);
}
return rv + enclen;
return nghttp2_hd_handle_buffer_error(rv);
}
static int emit_indname_block(nghttp2_buf *buf, size_t index,
static int emit_indname_block(nghttp2_bufs *bufs, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing)
{
@ -637,6 +645,7 @@ static int emit_indname_block(nghttp2_buf *buf, size_t index,
size_t encvallen;
size_t blocklen;
int huffman;
uint8_t sb[16];
encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
blocklen = count_encoded_length(index + 1, 6);
@ -646,41 +655,39 @@ static int emit_indname_block(nghttp2_buf *buf, size_t index,
encvallen = valuelen;
}
blocklen += count_encoded_length(encvallen, 7) + encvallen;
if(sizeof(sb) < blocklen) {
return NGHTTP2_ERR_HEADER_COMP;
}
rv = ensure_write_buffer(buf, blocklen);
bufp = sb;
*bufp = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, index + 1, 6);
rv = nghttp2_bufs_add(bufs, sb, blocklen);
if(rv != 0) {
return nghttp2_hd_handle_buffer_error(rv);
}
rv = emit_string(bufs, encvallen, huffman, value, valuelen);
if(rv != 0) {
return rv;
}
bufp = buf->last;
*bufp = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, index + 1, 6);
bufp += emit_string(bufp, buf->end - bufp,
encvallen, huffman, value, valuelen);
assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
return 0;
}
static int emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
static int emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int inc_indexing)
{
int rv;
uint8_t *bufp;
size_t encnamelen;
size_t encvallen;
size_t blocklen;
int name_huffman;
int value_huffman;
encnamelen = nghttp2_hd_huff_encode_count(nv->name, nv->namelen);
encvallen = nghttp2_hd_huff_encode_count(nv->value, nv->valuelen);
blocklen = 1;
name_huffman = encnamelen < nv->namelen;
value_huffman = encvallen < nv->valuelen;
@ -691,25 +698,20 @@ static int emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
encvallen = nv->valuelen;
}
blocklen += count_encoded_length(encnamelen, 7) + encnamelen +
count_encoded_length(encvallen, 7) + encvallen;
rv = nghttp2_bufs_addb(bufs, inc_indexing ? 0 : 0x40u);
if(rv != 0) {
return nghttp2_hd_handle_buffer_error(rv);
}
rv = ensure_write_buffer(buf, blocklen);
rv = emit_string(bufs, encnamelen, name_huffman, nv->name, nv->namelen);
if(rv != 0) {
return rv;
}
bufp = buf->last;
*bufp++ = inc_indexing ? 0 : 0x40u;
bufp += emit_string(bufp, buf->end - bufp,
encnamelen, name_huffman, nv->name, nv->namelen);
bufp += emit_string(bufp, buf->end - bufp,
encvallen, value_huffman, nv->value, nv->valuelen);
assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
rv = emit_string(bufs, encvallen, value_huffman, nv->value, nv->valuelen);
if(rv != 0) {
return rv;
}
return 0;
}
@ -718,12 +720,12 @@ static int emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
* Emit common header with |index| by toggle off and on (thus 2
* indexed representation emissions).
*/
static int emit_implicit(nghttp2_buf *buf, size_t index)
static int emit_implicit(nghttp2_bufs *bufs, size_t index)
{
int i, rv;
for(i = 0; i < 2; ++i) {
rv = emit_indexed_block(buf, index);
rv = emit_indexed_block(bufs, index);
if(rv != 0) {
return rv;
}
@ -732,7 +734,7 @@ static int emit_implicit(nghttp2_buf *buf, size_t index)
}
static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
nghttp2_buf *buf,
nghttp2_bufs *bufs,
nghttp2_nv *nv,
uint8_t entry_flags)
{
@ -754,7 +756,7 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
/* Emit common header just before it slips away from the
table. If we don't do this, we have to emit it in literal
representation which hurts compression. */
rv = emit_implicit(buf, index);
rv = emit_implicit(bufs, index);
if(rv != 0) {
return NULL;
}
@ -974,7 +976,7 @@ static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
}
static int deflate_nv(nghttp2_hd_deflater *deflater,
nghttp2_buf *buf, nghttp2_nv *nv)
nghttp2_bufs *bufs, nghttp2_nv *nv)
{
int rv;
nghttp2_hd_entry *ent;
@ -992,7 +994,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
/* It is important to first add entry to the header table and
let eviction go. If NGHTTP2_HD_FLAG_IMPLICIT_EMIT entry is
evicted, it must be emitted before the |nv|. */
new_ent = add_hd_table_incremental(&deflater->ctx, buf, &ent->nv,
new_ent = add_hd_table_incremental(&deflater->ctx, bufs, &ent->nv,
NGHTTP2_HD_FLAG_NONE);
if(!new_ent) {
return NGHTTP2_ERR_HEADER_COMP;
@ -1006,13 +1008,13 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
set */
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
}
rv = emit_indexed_block(buf, index);
rv = emit_indexed_block(bufs, index);
if(rv != 0) {
return rv;
}
} else if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) {
ent->flags |= NGHTTP2_HD_FLAG_REFSET | NGHTTP2_HD_FLAG_EMIT;
rv = emit_indexed_block(buf, index);
rv = emit_indexed_block(bufs, index);
if(rv != 0) {
return rv;
}
@ -1042,7 +1044,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
ent->flags |= NGHTTP2_HD_FLAG_IMPLICIT_EMIT;
}
for(; num_emits > 0; --num_emits) {
rv = emit_indexed_block(buf, index);
rv = emit_indexed_block(bufs, index);
if(rv != 0) {
break;
}
@ -1060,10 +1062,10 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
nghttp2_nv nv_indname;
nv_indname = *nv;
nv_indname.name = nghttp2_hd_table_get(&deflater->ctx, index)->nv.name;
new_ent = add_hd_table_incremental(&deflater->ctx, buf, &nv_indname,
new_ent = add_hd_table_incremental(&deflater->ctx, bufs, &nv_indname,
NGHTTP2_HD_FLAG_VALUE_ALLOC);
} else {
new_ent = add_hd_table_incremental(&deflater->ctx, buf, nv,
new_ent = add_hd_table_incremental(&deflater->ctx, bufs, nv,
NGHTTP2_HD_FLAG_NAME_ALLOC |
NGHTTP2_HD_FLAG_VALUE_ALLOC);
}
@ -1081,9 +1083,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
incidx = 1;
}
if(index == -1) {
rv = emit_newname_block(buf, nv, incidx);
rv = emit_newname_block(bufs, nv, incidx);
} else {
rv = emit_indname_block(buf, index, nv->value, nv->valuelen, incidx);
rv = emit_indname_block(bufs, index, nv->value, nv->valuelen, incidx);
}
if(rv != 0) {
return rv;
@ -1094,7 +1096,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
size_t index,
nghttp2_buf *buf)
nghttp2_bufs *bufs)
{
int rv;
@ -1105,7 +1107,7 @@ static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
be removed. */
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
rv = emit_indexed_block(buf, index);
rv = emit_indexed_block(bufs, index);
if(rv != 0) {
return rv;
}
@ -1116,22 +1118,20 @@ static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
return 0;
}
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_buf *buf,
nghttp2_nv *nv, size_t nvlen)
int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs,
nghttp2_nv *nv, size_t nvlen)
{
size_t i;
int rv = 0;
assert(nghttp2_buf_len(buf) == 0);
if(deflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP;
}
if(deflater->ctx.hd_table_bufsize_max >
deflater->deflate_hd_table_bufsize_max) {
rv = emit_table_size(buf, deflater->deflate_hd_table_bufsize_max);
rv = emit_table_size(bufs, deflater->deflate_hd_table_bufsize_max);
if(rv != 0) {
goto fail;
}
@ -1140,14 +1140,14 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
}
if(deflater->no_refset) {
rv = emit_clear_refset(buf);
rv = emit_clear_refset(bufs);
if(rv != 0) {
goto fail;
}
clear_refset(&deflater->ctx);
}
for(i = 0; i < nvlen; ++i) {
rv = deflate_nv(deflater, buf, &nv[i]);
rv = deflate_nv(deflater, bufs, &nv[i]);
if(rv != 0) {
goto fail;
}
@ -1155,13 +1155,13 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
for(i = 0; i < deflater->ctx.hd_table.len; ++i) {
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i);
rv = deflate_post_process_hd_entry(ent, i, buf);
rv = deflate_post_process_hd_entry(ent, i, bufs);
if(rv != 0) {
goto fail;
}
}
return nghttp2_buf_len(buf);
return 0;
fail:
deflater->ctx.bad = 1;
return rv;
@ -1788,20 +1788,20 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater)
return 0;
}
int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing)
{
return emit_indname_block(buf, index, value, valuelen, inc_indexing);
return emit_indname_block(bufs, index, value, valuelen, inc_indexing);
}
int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int inc_indexing)
{
return emit_newname_block(buf, nv, inc_indexing);
return emit_newname_block(bufs, nv, inc_indexing);
}
int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size)
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size)
{
return emit_table_size(buf, table_size);
return emit_table_size(bufs, table_size);
}

View File

@ -295,29 +295,29 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
/*
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
* the buffer pointed by the |buf|. The caller must ensure that
* nghttp2_buf_len(buf) == 0 holds. Write starts at buf->last.
* the |bufs|.
*
* This function expands |buf| as necessary to store the result.
* This function expands |bufs| as necessary to store the result. If
* buffers is full and the process still requires more space, this
* funtion fails and returns NGHTTP2_ERR_HEADER_COMP.
*
* This function copies necessary data into |buf|. After this function
* returns, it is safe to delete the |nva|.
* After this function returns, it is safe to delete the |nva|.
*
* TODO: The rest of the code call nghttp2_hd_end_headers() after this
* call, but it is just a regacy of the first implementation. Now it
* is not required to be called as of now.
*
* This function returns the number of bytes outputted if it succeeds,
* or one of the following negative error codes:
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_HEADER_COMP
* Deflation process has failed.
*/
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_buf *buf,
nghttp2_nv *nva, size_t nvlen);
int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs,
nghttp2_nv *nva, size_t nvlen);
typedef enum {
NGHTTP2_HD_INFLATE_NONE = 0,
@ -369,16 +369,16 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size);
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
/* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
@ -396,19 +396,19 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
/*
* Encodes the given data |src| with length |srclen| to the given
* memory location pointed by |dest|, allocated at lest |destlen|
* bytes. The caller is responsible to specify |destlen| at least the
* length that nghttp2_hd_huff_encode_count() returns.
* Encodes the given data |src| with length |srclen| to the |bufs|.
* This function expands extra buffers in |bufs| if necessary.
*
* This function returns the number of written bytes, including
* padding of prefix of terminal symbol code. This return value is
* exactly the same with the return value of
* nghttp2_hd_huff_encode_count() if it is given with the same |src|
* and |srclen|. This function always succeeds.
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen);
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);

View File

@ -40,24 +40,60 @@ extern const nghttp2_huff_decode huff_decode_table[][16];
* and points where next output should be placed. The number of
* unfilled bits in the pointed location is returned.
*/
static size_t huff_encode_sym(uint8_t **dest_ptr, size_t rembits,
const nghttp2_huff_sym *sym)
static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
size_t rembits,
const nghttp2_huff_sym *sym)
{
int rv;
size_t nbits = sym->nbits;
for(;;) {
if(rembits > nbits) {
**dest_ptr |= sym->code << (rembits - nbits);
if(*avail_ptr) {
nghttp2_bufs_fast_orb_hold(bufs, sym->code << (rembits - nbits));
} else {
rv = nghttp2_bufs_orb_hold(bufs, sym->code << (rembits - nbits));
if(rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
}
rembits -= nbits;
break;
}
**dest_ptr |= sym->code >> (nbits - rembits);
++*dest_ptr;
if(*avail_ptr) {
nghttp2_bufs_fast_orb(bufs, sym->code >> (nbits - rembits));
--*avail_ptr;
} else {
rv = nghttp2_bufs_orb(bufs, sym->code >> (nbits - rembits));
if(rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
}
nbits -= rembits;
rembits = 8;
if(nbits == 0) {
break;
}
**dest_ptr = 0;
if(*avail_ptr) {
nghttp2_bufs_fast_addb_hold(bufs, 0);
} else {
rv = nghttp2_bufs_addb_hold(bufs, 0);
if(rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
}
}
return rembits;
}
@ -74,27 +110,50 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len)
return (nbits + 7) / 8;
}
ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen,
const uint8_t *src, size_t srclen)
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
const uint8_t *src, size_t srclen)
{
int rv;
int rembits = 8;
uint8_t *dest_first = dest;
size_t i;
size_t avail;
avail = nghttp2_bufs_cur_avail(bufs);
for(i = 0; i < srclen; ++i) {
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]];
if(rembits == 8) {
*dest = 0;
if(avail) {
nghttp2_bufs_fast_addb_hold(bufs, 0);
} else {
rv = nghttp2_bufs_addb_hold(bufs, 0);
if(rv != 0) {
return rv;
}
avail = nghttp2_bufs_cur_avail(bufs);
}
}
rembits = huff_encode_sym(bufs, &avail, rembits, sym);
if(rembits < 0) {
return rembits;
}
rembits = huff_encode_sym(&dest, rembits, sym);
}
/* 256 is special terminal symbol, pad with its prefix */
if(rembits < 8) {
const nghttp2_huff_sym *sym = &huff_sym_table[256];
*dest |= sym->code >> (sym->nbits - rembits);
++dest;
/* Caution we no longer adjust avail here */
if(avail) {
nghttp2_bufs_fast_orb(bufs, sym->code >> (sym->nbits - rembits));
} else {
rv = nghttp2_bufs_orb(bufs, sym->code >> (sym->nbits - rembits));
if(rv != 0) {
return rv;
}
}
}
return dest - dest_first;
return 0;
}
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx)
@ -109,6 +168,10 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
{
size_t i, j;
int rv;
size_t avail;
avail = nghttp2_bufs_cur_avail(bufs);
/* We use the decoding algorithm described in
http://graphics.ics.uci.edu/pub/Prefix.pdf */
for(i = 0; i < srclen; ++i) {
@ -119,9 +182,15 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
return NGHTTP2_ERR_HEADER_COMP;
}
if(t->flags & NGHTTP2_HUFF_SYM) {
rv = nghttp2_bufs_addb(bufs, t->sym);
if(rv != 0) {
return rv;
if(avail) {
nghttp2_bufs_fast_addb(bufs, t->sym);
--avail;
} else {
rv = nghttp2_bufs_addb(bufs, t->sym);
if(rv != 0) {
return rv;
}
avail = nghttp2_bufs_cur_avail(bufs);
}
}
ctx->state = t->state;

View File

@ -211,7 +211,7 @@ static void nghttp2_active_outbound_item_reset
nghttp2_outbound_item_free(aob->item);
free(aob->item);
aob->item = NULL;
nghttp2_buf_reset(&aob->framebuf);
nghttp2_bufs_reset(&aob->framebufs);
aob->state = NGHTTP2_OB_POP_ITEM;
}
@ -290,8 +290,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
(*session_ptr)->server = 1;
}
rv = nghttp2_buf_init2(&(*session_ptr)->aob.framebuf,
NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH);
/* 2 for PAD_HIGH and PAD_LOW. We have maximum 64KB of frame
serialization buffer for transmission */
rv = nghttp2_bufs_init2(&(*session_ptr)->aob.framebufs,
NGHTTP2_MAX_FRAMELEN,
65536 / NGHTTP2_MAX_FRAMELEN,
NGHTTP2_FRAME_HDLEN + 2);
if(rv != 0) {
goto fail_aob_framebuf;
}
@ -418,7 +422,7 @@ void nghttp2_session_del(nghttp2_session *session)
nghttp2_hd_deflate_free(&session->hd_deflater);
nghttp2_hd_inflate_free(&session->hd_inflater);
nghttp2_active_outbound_item_reset(&session->aob);
nghttp2_buf_free(&session->aob.framebuf);
nghttp2_bufs_free(&session->aob.framebufs);
free(session);
}
@ -1124,47 +1128,20 @@ static ssize_t session_call_select_padding(nghttp2_session *session,
return frame->hd.length;
}
static int session_reserve_pad_trail(nghttp2_session *session, size_t padlen)
{
int rv;
nghttp2_active_outbound_item *aob;
if(padlen == 0) {
return 0;
}
aob = &session->aob;
DEBUGF(fprintf(stderr,
"reserving extra %zu padding bytes, including garbage, "
"but adjusted later\n",
padlen));
rv = nghttp2_buf_last_reserve(&aob->framebuf, padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
/* We have to zero out padding bytes so that we won't reveal the
possible internal data to the remote peer */
memset(aob->framebuf.last, 0, padlen);
aob->framebuf.last += padlen;
return 0;
}
/* Add padding to HEADERS or PUSH_PROMISE. We use
frame->headers.padlen in this function to use the fact that
frame->push_promise has also padlen in the same position. */
static ssize_t session_headers_add_pad(nghttp2_session *session,
nghttp2_frame *frame)
static int session_headers_add_pad(nghttp2_session *session,
nghttp2_frame *frame)
{
int rv;
ssize_t padded_payloadlen;
nghttp2_active_outbound_item *aob;
nghttp2_bufs *framebufs;
size_t padlen;
aob = &session->aob;
framebufs = &aob->framebufs;
padded_payloadlen = session_call_select_padding(session, frame,
frame->hd.length + 1024);
@ -1172,70 +1149,20 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
return padded_payloadlen;
}
frame->headers.padlen = padded_payloadlen - frame->hd.length;
frame->hd.length = padded_payloadlen;
padlen = padded_payloadlen - frame->hd.length;
DEBUGF(fprintf(stderr, "padding selected: payloadlen=%zu, padlen=%zu\n",
frame->hd.length, frame->headers.padlen));
padded_payloadlen, padlen));
if(frame->hd.length > NGHTTP2_MAX_PAYLOADLEN) {
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_PAYLOADLEN;
if(NGHTTP2_MAX_PAYLOADLEN > frame->hd.length - frame->headers.padlen) {
size_t padlen;
padlen = NGHTTP2_MAX_PAYLOADLEN -
(frame->hd.length - frame->headers.padlen);
DEBUGF(fprintf(stderr, "padding across 2 frames\n"));
DEBUGF(fprintf(stderr, "first HEADERS/PUSH_PROMISE "
"payloadlen=%zu, padlen=%zu\n", hd.length, padlen));
rv = session_reserve_pad_trail(session, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
nghttp2_frame_set_pad(&aob->framebuf, &hd.flags, padlen);
} else {
/* PAD_HIGH and PAD_LOW will be added in
nghttp2_session_after_frame_sent(). */
DEBUGF(fprintf(stderr,
"first HEADERS/PUSH_PROMISE does not have "
"padding payloadlen=%zu", hd.length));
/* Ensure that we have allocated buffer */
rv = session_reserve_pad_trail(session, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
}
nghttp2_frame_pack_frame_hd(aob->framebuf.pos, &hd);
} else if(frame->headers.padlen > 0) {
nghttp2_frame_hd hd = frame->hd;
rv = session_reserve_pad_trail(session, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
DEBUGF(fprintf(stderr,
"first HEADERS/PUSH_PROMISE payloadlen=%zu, padlen=%zu\n",
frame->hd.length, frame->headers.padlen));
nghttp2_frame_set_pad(&aob->framebuf, &hd.flags, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
nghttp2_frame_pack_frame_hd(aob->framebuf.pos, &hd);
rv = nghttp2_frame_add_pad(framebufs, &frame->hd, padlen,
NGHTTP2_CONTINUATION);
if(rv != 0) {
return rv;
}
return nghttp2_buf_len(&session->aob.framebuf);
frame->headers.padlen = padlen;
return 0;
}
/*
@ -1281,7 +1208,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
return rv;
}
}
framebuflen = nghttp2_frame_pack_headers(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_headers(&session->aob.framebufs,
&frame->headers,
&session->hd_deflater);
if(framebuflen < 0) {
@ -1290,7 +1217,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
DEBUGF(fprintf(stderr,
"before padding, HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
nghttp2_bufs_len(&session->aob.framebufs)));
framebuflen = session_headers_add_pad(session, frame);
if(framebuflen < 0) {
@ -1320,7 +1247,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
}
DEBUGF(fprintf(stderr, "HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
nghttp2_bufs_len(&session->aob.framebufs)));
break;
}
@ -1330,7 +1257,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
if(rv != 0) {
return rv;
}
framebuflen = nghttp2_frame_pack_priority(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_priority(&session->aob.framebufs,
&frame->priority);
if(framebuflen < 0) {
return framebuflen;
@ -1338,7 +1265,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
break;
}
case NGHTTP2_RST_STREAM:
framebuflen = nghttp2_frame_pack_rst_stream(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_rst_stream(&session->aob.framebufs,
&frame->rst_stream);
if(framebuflen < 0) {
return framebuflen;
@ -1349,7 +1276,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
if(rv != 0) {
return rv;
}
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebufs,
&frame->settings);
if(framebuflen < 0) {
return framebuflen;
@ -1368,7 +1295,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
}
frame->push_promise.promised_stream_id = session->next_stream_id;
session->next_stream_id += 2;
framebuflen = nghttp2_frame_pack_push_promise(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_push_promise(&session->aob.framebufs,
&frame->push_promise,
&session->hd_deflater);
if(framebuflen < 0) {
@ -1393,7 +1320,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
break;
}
case NGHTTP2_PING:
framebuflen = nghttp2_frame_pack_ping(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_ping(&session->aob.framebufs,
&frame->ping);
if(framebuflen < 0) {
return framebuflen;
@ -1405,7 +1332,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
if(rv != 0) {
return rv;
}
framebuflen = nghttp2_frame_pack_window_update(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_window_update(&session->aob.framebufs,
&frame->window_update);
if(framebuflen < 0) {
return framebuflen;
@ -1420,7 +1347,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
peer that last-stream-id. */
return NGHTTP2_ERR_GOAWAY_ALREADY_SENT;
}
framebuflen = nghttp2_frame_pack_goaway(&session->aob.framebuf,
framebuflen = nghttp2_frame_pack_goaway(&session->aob.framebufs,
&frame->goaway);
if(framebuflen < 0) {
return framebuflen;
@ -1450,7 +1377,7 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_DEFERRED;
}
framebuflen = nghttp2_session_pack_data(session,
&session->aob.framebuf,
&session->aob.framebufs,
next_readmax,
data_frame);
if(framebuflen == NGHTTP2_ERR_DEFERRED) {
@ -1603,7 +1530,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
int rv;
nghttp2_active_outbound_item *aob = &session->aob;
nghttp2_outbound_item *item = aob->item;
nghttp2_buf *framebuf = &aob->framebuf;
nghttp2_bufs *framebufs = &aob->framebufs;
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame;
@ -1613,63 +1540,11 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
if(frame->hd.type == NGHTTP2_HEADERS ||
frame->hd.type == NGHTTP2_PUSH_PROMISE) {
if(framebuf->mark < framebuf->last) {
nghttp2_frame_hd cont_hd;
if(nghttp2_bufs_next_present(framebufs)) {
framebufs->cur = framebufs->cur->next;
cont_hd.length = nghttp2_min(framebuf->last - framebuf->mark,
NGHTTP2_MAX_PAYLOADLEN);
cont_hd.type = NGHTTP2_CONTINUATION;
cont_hd.stream_id = frame->hd.stream_id;
cont_hd.flags = NGHTTP2_FLAG_NONE;
/* Reuse previous buffers for frame header */
framebuf->pos -= NGHTTP2_FRAME_HDLEN;
if(cont_hd.length + framebuf->mark == framebuf->last) {
size_t padlen;
if(cont_hd.length < frame->headers.padlen) {
padlen = cont_hd.length;
} else {
/* We use frame->headers.padlen for PUSH_PROMISE too. This
is possible because padlen is located in the same
position. */
padlen = frame->headers.padlen;
}
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
DEBUGF(fprintf(stderr,
"last CONTINUATION payloadlen=%zu, padlen=%zu\n",
cont_hd.length, padlen));
nghttp2_frame_set_pad(framebuf, &cont_hd.flags, padlen);
framebuf->mark = framebuf->last;
} else {
ssize_t padlen;
framebuf->mark += cont_hd.length;
padlen = frame->headers.padlen - (framebuf->last - framebuf->mark);
if(padlen > 0) {
/* frame payload includes a part of padding */
DEBUGF(fprintf(stderr,
"padding across 2 CONTINUATION frames. "
"payloadlen=%zu, padlen=%zd\n",
cont_hd.length, padlen));
nghttp2_frame_set_pad(framebuf, &cont_hd.flags, padlen);
framebuf->mark = framebuf->pos + NGHTTP2_FRAME_HDLEN +
cont_hd.length;
} else {
/* If no padding, nothing to be done here */
}
}
nghttp2_frame_pack_frame_hd(framebuf->pos, &cont_hd);
DEBUGF(fprintf(stderr, "send CONTINUATION frame, %zu bytes\n",
nghttp2_buf_len(&framebufs->cur->buf)));
return 0;
}
@ -1865,7 +1740,10 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
return 0;
}
rv = nghttp2_session_pack_data(session, framebuf, next_readmax,
nghttp2_bufs_reset(framebufs);
rv = nghttp2_session_pack_data(session, framebufs, next_readmax,
data_frame);
if(nghttp2_is_fatal(rv)) {
return rv;
@ -1892,7 +1770,6 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
return 0;
}
assert(rv >= 0);
framebuf->mark = framebuf->last;
return 0;
}
@ -1916,10 +1793,10 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
{
int rv;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
nghttp2_bufs *framebufs;
aob = &session->aob;
framebuf = &aob->framebuf;
framebufs = &aob->framebufs;
*data_ptr = NULL;
for(;;) {
@ -1974,29 +1851,22 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
}
aob->item = item;
nghttp2_bufs_rewind(framebufs);
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame;
/* We have to get frame size from headers, because
frame->hd.length does not always shows the actual frame
size, especially for HEADERS size >
NGHTTP2_MAX_PAYLOADLEN */
frame = nghttp2_outbound_item_get_ctrl_frame(item);
framebuf->mark = framebuf->pos + NGHTTP2_FRAME_HDLEN +
nghttp2_get_uint16(framebuf->pos);
rv = session_call_before_frame_send(session, frame);
if(nghttp2_is_fatal(rv)) {
return rv;
}
} else {
framebuf->mark = framebuf->last;
}
DEBUGF(fprintf(stderr, "start transmitting type %d frame %zd bytes\n",
framebuf->pos[2], framebuf->mark - framebuf->pos));
framebufs->cur->buf.pos[2],
framebufs->cur->buf.last - framebufs->cur->buf.pos));
aob->state = NGHTTP2_OB_SEND_DATA;
@ -2004,10 +1874,12 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
}
case NGHTTP2_OB_SEND_DATA: {
size_t datalen;
nghttp2_buf *buf;
if(framebuf->pos == framebuf->mark) {
DEBUGF(fprintf(stderr, "end transmission of frame, left %zd\n",
framebuf->last - framebuf->mark));
buf = &framebufs->cur->buf;
if(buf->pos == buf->last) {
DEBUGF(fprintf(stderr, "end transmission of frame\n"));
/* Frame has completely sent */
rv = nghttp2_session_after_frame_sent(session);
@ -2020,11 +1892,12 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
break;
}
*data_ptr = framebuf->pos;
datalen = framebuf->mark - framebuf->pos;
*data_ptr = buf->pos;
datalen = nghttp2_buf_len(buf);
/* We increment the offset here. If send_callback does not send
everything, we will adjust it. */
framebuf->pos += datalen;
buf->pos += datalen;
return datalen;
}
@ -2037,9 +1910,9 @@ int nghttp2_session_send(nghttp2_session *session)
const uint8_t *data;
ssize_t datalen;
ssize_t sentlen;
nghttp2_buf *framebuf;
nghttp2_bufs *framebufs;
framebuf = &session->aob.framebuf;
framebufs = &session->aob.framebufs;
for(;;) {
datalen = nghttp2_session_mem_send(session, &data);
@ -2051,15 +1924,16 @@ int nghttp2_session_send(nghttp2_session *session)
if(sentlen < 0) {
if(sentlen == NGHTTP2_ERR_WOULDBLOCK) {
/* Transmission canceled. Rewind the offset */
framebuf->pos -= datalen;
framebufs->cur->buf.pos -= datalen;
return 0;
}
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
/* Rewind the offset to the amount of unsent bytes */
framebuf->pos -= datalen - sentlen;
framebufs->cur->buf.pos -= datalen - sentlen;
}
return 0;
}
@ -4572,36 +4446,30 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
}
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
nghttp2_buf *buf,
nghttp2_bufs *bufs,
size_t datamax,
nghttp2_private_data *frame)
{
ssize_t framelen;
ssize_t rv;
int eof_flags;
uint8_t flags;
ssize_t payloadlen;
ssize_t padded_payloadlen;
size_t padlen;
nghttp2_frame data_frame;
nghttp2_frame data_frame = {{0}}; /* FIXME padlen is also initialized? */
nghttp2_frame_hd hd;
nghttp2_buf *buf;
/* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes
for padding. Based on the padding length, we adjust the starting
offset of frame data. The starting offset is assigned into
|*bufoff_ptr|. */
buf->pos += 2;
assert(bufs->head == bufs->cur);
framelen = NGHTTP2_FRAME_HDLEN + datamax;
buf = &bufs->cur->buf;
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
/* Current max DATA length is less then buffer chunk size */
assert(nghttp2_buf_avail(buf) >= (ssize_t)datamax);
eof_flags = 0;
payloadlen = frame->data_prd.read_callback
(session, frame->hd.stream_id, buf->pos + NGHTTP2_FRAME_HDLEN, datamax,
(session, frame->hd.stream_id, buf->pos, datamax,
&eof_flags, &frame->data_prd.source, session->user_data);
if(payloadlen == NGHTTP2_ERR_DEFERRED ||
@ -4617,7 +4485,8 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
buf->last = buf->pos + NGHTTP2_FRAME_HDLEN + payloadlen;
buf->last = buf->pos + payloadlen;
buf->pos -= NGHTTP2_FRAME_HDLEN;
/* Clear flags, because this may contain previous flags of previous
DATA */
@ -4635,8 +4504,6 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
}
/* The primary reason of data_frame is pass to the user callback */
memset(&data_frame, 0, sizeof(data_frame));
data_frame.hd.length = payloadlen;
data_frame.hd.stream_id = frame->hd.stream_id;
data_frame.hd.type = NGHTTP2_DATA;
@ -4650,27 +4517,21 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
padlen = padded_payloadlen - payloadlen;
rv = session_reserve_pad_trail(session, padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
nghttp2_frame_set_pad(buf, &flags, padlen);
frame->padlen = padlen;
frame->hd.length = padded_payloadlen;
/* Set PAD flags so that we can supply frame to the callback with
the correct flags */
frame->hd.flags |= flags;
memset(buf->pos, 0, NGHTTP2_FRAME_HDLEN);
hd = frame->hd;
hd.length = payloadlen;
hd.flags = flags;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
rv = nghttp2_frame_add_pad(bufs, &hd, padlen, NGHTTP2_DATA);
if(rv != 0) {
return rv;
}
frame->hd.length = hd.length;
frame->hd.flags |= hd.flags;
frame->padlen = padlen;
return nghttp2_buf_len(buf);
}

View File

@ -55,15 +55,13 @@ typedef enum {
typedef struct {
nghttp2_outbound_item *item;
nghttp2_buf framebuf;
nghttp2_bufs framebufs;
nghttp2_outbound_state state;
} nghttp2_active_outbound_item;
/* Buffer length for inbound raw byte stream. */
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
#define NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH 16384
#define NGHTTP2_INITIAL_NV_BUFFER_LENGTH 4096
/* Internal state when receiving incoming frame */
@ -526,7 +524,7 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
* The read_callback failed (session error).
*/
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
nghttp2_buf *buf,
nghttp2_bufs *bufs,
size_t datamax,
nghttp2_private_data *frame);

View File

@ -290,9 +290,9 @@ cdef extern from 'nghttp2_hd.h':
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t hd_table_bufsize_max)
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_buf *buf,
nghttp2_nv *nva, size_t nvlen)
int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs,
nghttp2_nv *nva, size_t nvlen)
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
nghttp2_nv *nv_out, int *inflate_flags,
@ -305,11 +305,12 @@ cdef extern from 'nghttp2_hd.h':
cdef extern from 'nghttp2_buf.h':
ctypedef struct nghttp2_buf:
uint8_t *pos
uint8_t *last
ctypedef struct nghttp2_bufs:
pass
void nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_size,
size_t max_chunk)
void nghttp2_buf_init(nghttp2_buf *buf)
void nghttp2_bufs_free(nghttp2_bufs *bufs)
void nghttp2_buf_free(nghttp2_buf *buf)
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)

View File

@ -114,27 +114,36 @@ cdef class HDDeflater:
nvap[0].valuelen = len(v)
nvap += 1
cdef cnghttp2.nghttp2_buf buf
cdef cnghttp2.nghttp2_bufs bufs
cdef size_t outcap = 0
cdef ssize_t rv
cdef uint8_t *out
cnghttp2.nghttp2_buf_init(&buf)
cnghttp2.nghttp2_bufs_init(&bufs, 4096, 16)
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &buf,
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &bufs,
nva, len(headers))
free(nva)
if rv < 0:
cnghttp2.nghttp2_buf_free(&buf);
cnghttp2.nghttp2_bufs_free(&bufs);
raise Exception(_strerror(rv))
rv = cnghttp2.nghttp2_bufs_remove(&bufs, &out)
if rv < 0:
cnghttp2.nghttp2_bufs_free(&bufs);
raise Exception(_strerror(rv))
cdef bytes res
try:
res = buf.pos[:rv]
res = out[:rv]
finally:
cnghttp2.nghttp2_buf_free(&buf)
cnghttp2.nghttp2_free(out)
cnghttp2.nghttp2_bufs_free(&bufs)
return res

View File

@ -324,7 +324,7 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
}
switch(frame->hd.type) {
case NGHTTP2_DATA:
if(frame->hd.flags & (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW)) {
if(frame->data.padlen > 0) {
print_frame_attr_indent();
fprintf(outfile, "(padlen=%zu)\n", frame->data.padlen);
}

View File

@ -72,26 +72,36 @@ static void to_hex(char *dest, const uint8_t *src, size_t len)
}
static void output_to_json(nghttp2_hd_deflater *deflater,
nghttp2_buf *buf, size_t inputlen,
nghttp2_bufs *bufs, size_t inputlen,
nghttp2_nv *nva, size_t nvlen,
int seq)
{
json_t *obj;
char *hex = NULL;
char *hex = NULL, *hexp;
size_t len;
nghttp2_buf_chain *ci;
nghttp2_buf *buf;
len = nghttp2_buf_len(buf);
len = nghttp2_bufs_len(bufs);
if(len > 0) {
hex = malloc(len * 2);
}
obj = json_object();
json_object_set_new(obj, "seq", json_integer(seq));
json_object_set_new(obj, "input_length", json_integer(inputlen));
json_object_set_new(obj, "output_length", json_integer(len));
json_object_set_new(obj, "percentage_of_original_size",
json_real((double)len / inputlen * 100));
to_hex(hex, buf->pos, len);
hexp = hex;
for(ci = bufs->head; ci; ci = ci->next) {
buf = &ci->buf;
to_hex(hexp, buf->pos, nghttp2_buf_len(buf));
hexp += nghttp2_buf_len(buf);
}
if(len == 0) {
json_object_set_new(obj, "wire", json_string(""));
} else {
@ -117,11 +127,11 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_nv *nva, size_t nvlen, size_t inputlen, int seq)
{
ssize_t rv;
nghttp2_buf buf;
nghttp2_bufs bufs;
nghttp2_buf_init(&buf);
nghttp2_bufs_init2(&bufs, 4096, 16, 0);
rv = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
rv = nghttp2_hd_deflate_hd(deflater, &bufs, nva, nvlen);
if(rv < 0) {
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE);
@ -130,8 +140,8 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
input_sum += inputlen;
output_sum += rv;
output_to_json(deflater, &buf, inputlen, nva, nvlen, seq);
nghttp2_buf_free(&buf);
output_to_json(deflater, &bufs, inputlen, nva, nvlen, seq);
nghttp2_bufs_free(&bufs);
}
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)

View File

@ -72,14 +72,14 @@ void test_nghttp2_frame_pack_headers()
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_headers frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
nghttp2_nv *nva;
ssize_t nvlen;
nva_out out;
ssize_t hdblocklen;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater);
@ -91,22 +91,24 @@ void test_nghttp2_frame_pack_headers()
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007,
1 << 20, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
nghttp2_bufs_rewind(&bufs);
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS,
1000000007, &oframe.hd);
/* We didn't include PRIORITY flag so priority is not packed */
CU_ASSERT(1 << 30 == oframe.pri);
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN;
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf.pos + NGHTTP2_FRAME_HDLEN, hdblocklen));
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN));
CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
@ -114,33 +116,33 @@ void test_nghttp2_frame_pack_headers()
nghttp2_frame_headers_free(&oframe);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
memset(&oframe, 0, sizeof(oframe));
/* Next, include PRIORITY flag */
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY,
1000000007, &oframe.hd);
CU_ASSERT(1 << 20 == oframe.pri);
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN + 4));
nghttp2_nv_array_sort(out.nva, out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
nva_out_reset(&out);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_headers_free(&oframe);
nghttp2_frame_headers_free(&frame);
nghttp2_hd_inflate_free(&inflater);
@ -151,16 +153,16 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
{
nghttp2_hd_deflater deflater;
nghttp2_headers frame;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
nghttp2_nv *nva;
ssize_t nvlen;
size_t big_vallen = NGHTTP2_HD_MAX_VALUE;
nghttp2_nv big_hds[16];
size_t big_hdslen = ARRLEN(big_hds);
size_t i;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
for(i = 0; i < big_hdslen; ++i) {
big_hds[i].name = (uint8_t*)"header";
@ -177,11 +179,11 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007,
0, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen);
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == rv);
nghttp2_frame_headers_free(&frame);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
for(i = 0; i < big_hdslen; ++i) {
free(big_hds[i].value);
}
@ -191,21 +193,22 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
void test_nghttp2_frame_pack_priority(void)
{
nghttp2_priority frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_frame_priority_init(&frame, 1000000007, 1 << 30);
framelen = nghttp2_frame_pack_priority(&buf, &frame);
rv = nghttp2_frame_pack_priority(&bufs, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(12 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd);
CU_ASSERT(1 << 30 == oframe.pri);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_priority_free(&oframe);
nghttp2_frame_priority_free(&frame);
}
@ -213,21 +216,22 @@ void test_nghttp2_frame_pack_priority(void)
void test_nghttp2_frame_pack_rst_stream(void)
{
nghttp2_rst_stream frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_frame_rst_stream_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR);
framelen = nghttp2_frame_pack_rst_stream(&buf, &frame);
rv = nghttp2_frame_pack_rst_stream(&bufs, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(12 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd);
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_rst_stream_free(&oframe);
nghttp2_frame_rst_stream_free(&frame);
}
@ -235,9 +239,9 @@ void test_nghttp2_frame_pack_rst_stream(void)
void test_nghttp2_frame_pack_settings()
{
nghttp2_settings frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
int i;
int rv;
nghttp2_settings_entry iv[] =
{
{
@ -251,17 +255,17 @@ void test_nghttp2_frame_pack_settings()
}
};
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE,
nghttp2_frame_iv_copy(iv, 3), 3);
framelen = nghttp2_frame_pack_settings(&buf, &frame);
rv = nghttp2_frame_pack_settings(&bufs, &frame);
CU_ASSERT(NGHTTP2_FRAME_HDLEN +
3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(NGHTTP2_FRAME_HDLEN + 3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH ==
nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
CU_ASSERT(3 == oframe.niv);
@ -270,7 +274,7 @@ void test_nghttp2_frame_pack_settings()
CU_ASSERT(iv[i].value == oframe.iv[i].value);
}
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_settings_free(&frame);
nghttp2_frame_settings_free(&oframe);
}
@ -280,14 +284,14 @@ void test_nghttp2_frame_pack_push_promise()
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_push_promise frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
nghttp2_nv *nva;
ssize_t nvlen;
nva_out out;
ssize_t hdblocklen;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater);
@ -297,27 +301,27 @@ void test_nghttp2_frame_pack_push_promise()
nvlen = HEADERS_LENGTH;
nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_HEADERS,
1000000007, (1U << 31) - 1, nva, nvlen);
framelen = nghttp2_frame_pack_push_promise(&buf, &frame, &deflater);
rv = nghttp2_frame_pack_push_promise(&bufs, &frame, &deflater);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_PUSH_PROMISE,
NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd);
CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id);
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN + 4));
CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
CU_ASSERT(nvvalueeq("GET", &out.nva[0]));
nva_out_reset(&out);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_push_promise_free(&oframe);
nghttp2_frame_push_promise_free(&frame);
nghttp2_hd_inflate_free(&inflater);
@ -327,22 +331,23 @@ void test_nghttp2_frame_pack_push_promise()
void test_nghttp2_frame_pack_ping(void)
{
nghttp2_ping frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
const uint8_t opaque_data[] = "01234567";
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data);
framelen = nghttp2_frame_pack_ping(&buf, &frame);
rv = nghttp2_frame_pack_ping(&bufs, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(16 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_ACK, 0, &oframe.hd);
CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, sizeof(opaque_data) - 1)
== 0);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_ping_free(&oframe);
nghttp2_frame_ping_free(&frame);
}
@ -350,20 +355,21 @@ void test_nghttp2_frame_pack_ping(void)
void test_nghttp2_frame_pack_goaway()
{
nghttp2_goaway frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
size_t opaque_data_len = 16;
uint8_t *opaque_data = malloc(opaque_data_len);
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memcpy(opaque_data, "0123456789abcdef", opaque_data_len);
nghttp2_frame_goaway_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR,
opaque_data, opaque_data_len);
framelen = nghttp2_frame_pack_goaway(&buf, &frame);
rv = nghttp2_frame_pack_goaway(&bufs, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT((ssize_t)(16 + opaque_data_len) == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(24, NGHTTP2_GOAWAY, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
CU_ASSERT(1000000007 == oframe.last_stream_id);
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code);
@ -373,7 +379,7 @@ void test_nghttp2_frame_pack_goaway()
/* CU_ASSERT(opaque_data_len == oframe.opaque_data_len); */
/* CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, opaque_data_len) == 0); */
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_goaway_free(&oframe);
nghttp2_frame_goaway_free(&frame);
}
@ -381,22 +387,23 @@ void test_nghttp2_frame_pack_goaway()
void test_nghttp2_frame_pack_window_update(void)
{
nghttp2_window_update frame, oframe;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_frame_window_update_init(&frame, NGHTTP2_FLAG_NONE,
1000000007, 4096);
framelen = nghttp2_frame_pack_window_update(&buf, &frame);
rv = nghttp2_frame_pack_window_update(&bufs, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
CU_ASSERT(0 == rv);
CU_ASSERT(12 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(4, NGHTTP2_WINDOW_UPDATE, NGHTTP2_FLAG_NONE,
1000000007, &oframe.hd);
CU_ASSERT(4096 == oframe.window_size_increment);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_window_update_free(&oframe);
nghttp2_frame_window_update_free(&frame);
}

View File

@ -52,83 +52,89 @@ void test_nghttp2_hd_deflate(void)
MAKE_NV("cookie", "k1=v1")};
nghttp2_nv nva5[] = {MAKE_NV(":path", "/style.css"),
MAKE_NV("x-nghttp2", "")};
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nva_out out;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva1, ARRLEN(nva1));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva1, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Second headers */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva2, ARRLEN(nva2));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva2, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Third headers, including same header field name, but value is not
the same. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva3, ARRLEN(nva3));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva3, ARRLEN(nva3));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva3, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Fourth headers, including duplicate header fields. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva4, ARRLEN(nva4));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva4, ARRLEN(nva4));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva4, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Fifth headers includes empty value */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva5, ARRLEN(nva5));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva5, ARRLEN(nva5));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva5, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Cleanup */
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -142,11 +148,12 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
nghttp2_nv nva2[] = {MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha")};
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nva_out out;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
@ -154,34 +161,36 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
/* Encode 2 same headers. cookie:alpha is not in the reference set,
so first emit literal repr and then 2 emits of indexed repr. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva1, ARRLEN(nva1));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva1, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Encode 3 same headers. This time, cookie:alpha is in the
reference set, so the encoder emits indexed repr 6 times */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva2, ARRLEN(nva2));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen == 6);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva2, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Cleanup */
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -192,7 +201,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = {MAKE_NV("h1", ""),
MAKE_NV("h2", "")};
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
/* Default header table capacity is 4096. Adding 2 byte header name
and 4060 byte value, which is 4094 bytes including overhead, to
@ -200,8 +209,9 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
uint8_t value[3038];
nva_out out;
size_t i;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
memset(value, '0', sizeof(value));
@ -215,42 +225,44 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
/* First emit "h1: ..." to put it in the reference set (index
= 0). */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 1);
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 1);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
nghttp2_nv_array_sort(nva, 1);
assert_nv_equal(nva, out.nva, 1);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Encode with second header */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
/* Check common header "h1: ...:, which is removed from the
header table because of eviction, is still emitted by the
inflater */
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == out.nvlen);
nghttp2_nv_array_sort(nva, 2);
assert_nv_equal(nva, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
CU_ASSERT(1 == deflater.ctx.hd_table.len);
CU_ASSERT(1 == inflater.ctx.hd_table.len);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -259,7 +271,7 @@ void test_nghttp2_hd_deflate_clear_refset(void)
{
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv[] = {
MAKE_NV(":path", "/"),
@ -267,8 +279,9 @@ void test_nghttp2_hd_deflate_clear_refset(void)
};
size_t i;
nva_out out;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_deflate_init2(&deflater,
@ -277,18 +290,21 @@ void test_nghttp2_hd_deflate_clear_refset(void)
nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < 2; ++i) {
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nv, ARRLEN(nv));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nv, ARRLEN(nv));
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 1);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(ARRLEN(nv) == out.nvlen);
assert_nv_equal(nv, out.nva, ARRLEN(nv));
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
}
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -296,7 +312,7 @@ void test_nghttp2_hd_deflate_clear_refset(void)
void test_nghttp2_hd_inflate_indname_noinc(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv[] = {
/* Huffman */
@ -307,53 +323,53 @@ void test_nghttp2_hd_inflate_indname_noinc(void)
size_t i;
nva_out out;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) {
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 56,
nv[i].value, nv[i].valuelen,
0));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv[i], out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
}
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_inc(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nva_out out;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 56,
nv.value, nv.valuelen, 1));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
@ -363,38 +379,38 @@ void test_nghttp2_hd_inflate_indname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_inc_eviction(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
uint8_t value[1024];
nva_out out;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 13,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 13,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 14,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 14,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 15,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 15,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 16,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 16,
value, sizeof(value), 1));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(4 == out.nvlen);
CU_ASSERT(14 == out.nva[0].namelen);
@ -402,19 +418,19 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
CU_ASSERT(sizeof(value) == out.nva[0].valuelen);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
CU_ASSERT(3 == inflater.ctx.hd_table.len);
CU_ASSERT(GET_TABLE_ENT(&inflater.ctx, 0)->flags & NGHTTP2_HD_FLAG_REFSET);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_noinc(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv[] = {
/* Expecting huffman for both */
@ -429,49 +445,49 @@ void test_nghttp2_hd_inflate_newname_noinc(void)
size_t i;
nva_out out;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) {
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv[i], 0));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv[i], 0));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv[i], out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
}
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_inc(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nva_out out;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
@ -481,20 +497,20 @@ void test_nghttp2_hd_inflate_newname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_clearall_inc(void)
{
nghttp2_hd_inflater inflater;
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nghttp2_nv nv;
uint8_t value[4060];
nva_out out;
nghttp2_buf_init(&buf);
bufs_large_init(&bufs, 8192);
nva_out_init(&out);
/* Total 4097 bytes space required to hold this entry */
@ -506,66 +522,73 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Do it again */
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out);
nghttp2_bufs_reset(&bufs);
/* This time, 4096 bytes space required, which is just fits in the
header table */
nv.valuelen = sizeof(value) - 1;
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
CU_ASSERT(1 == inflater.ctx.hd_table.len);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_zero_length_huffman(void)
{
nghttp2_hd_inflater inflater;
uint8_t buf[4];
nghttp2_bufs bufs;
/* Literal header without indexing - new name */
uint8_t data[] = { 0x40, 0x01, 0x78 /* 'x' */, 0x80 };
nva_out out;
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
/* Literal header without indexing - new name */
buf[0] = 0x40;
buf[1] = 1;
buf[2] = 'x';
buf[3] = 0x80;
nghttp2_bufs_add(&bufs, data, sizeof(data));
/* /\* Literal header without indexing - new name *\/ */
/* ptr[0] = 0x40; */
/* ptr[1] = 1; */
/* ptr[2] = 'x'; */
/* ptr[3] = 0x80; */
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(4 == inflate_hd(&inflater, &out, buf, 4));
CU_ASSERT(4 == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(1 == out.nvlen);
CU_ASSERT(1 == out.nva[0].namelen);
@ -574,6 +597,7 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void)
CU_ASSERT(0 == out.nva[0].valuelen);
nva_out_reset(&out);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
}
@ -583,11 +607,12 @@ void test_nghttp2_hd_change_table_size(void)
nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = { MAKE_NV(":method", "GET"),
MAKE_NV(":path", "/") };
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t rv;
nva_out out;
ssize_t blocklen;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
@ -606,19 +631,21 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
/* This will emit encoding context update with header table size 4096 */
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* inflater changes header table size to 1024 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024));
@ -631,19 +658,21 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(0 == blocklen);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* inflater changes header table size to 0 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0));
@ -658,26 +687,28 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(0 == deflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(0 == inflater.ctx.hd_table.len);
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
/* Check table buffer is expanded */
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_hd_deflate_init2(&deflater, 8192);
nghttp2_hd_inflate_init(&inflater);
@ -693,19 +724,21 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383));
@ -717,29 +750,30 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Lastly, check the error condition */
rv = nghttp2_hd_emit_table_size(&buf, 25600);
rv = nghttp2_hd_emit_table_size(&bufs, 25600);
CU_ASSERT(rv == 0);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP ==
inflate_hd(&inflater, &out, buf.pos, nghttp2_buf_len(&buf)));
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == inflate_hd(&inflater, &out, &bufs, 0));
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
@ -753,21 +787,23 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
/* This emits context update with buffer size 1024 */
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen > 0);
CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0));
CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(4096 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -776,25 +812,27 @@ static void check_deflate_inflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater,
nghttp2_nv *nva, size_t nvlen)
{
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t blocklen;
nva_out out;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
blocklen = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
rv = nghttp2_hd_deflate_hd(deflater, &bufs, nva, nvlen);
blocklen = nghttp2_bufs_len(&bufs);
CU_ASSERT(0 == rv);
CU_ASSERT(blocklen >= 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(inflater, &out, buf.pos, blocklen));
CU_ASSERT(blocklen == inflate_hd(inflater, &out, &bufs, 0));
CU_ASSERT(nvlen == out.nvlen);
assert_nv_equal(nva, out.nva, nvlen);
nva_out_reset(&out);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
}
void test_nghttp2_hd_deflate_inflate(void)

View File

@ -75,14 +75,27 @@ typedef struct {
size_t padding_boundary;
} my_user_data;
static void scripted_data_feed_init(scripted_data_feed *df,
uint8_t *data, size_t data_length)
static void scripted_data_feed_init2(scripted_data_feed *df,
nghttp2_bufs *bufs)
{
nghttp2_buf_chain *ci;
nghttp2_buf *buf;
uint8_t *ptr;
size_t len;
memset(df, 0, sizeof(scripted_data_feed));
memcpy(df->data, data, data_length);
ptr = df->data;
len = 0;
for(ci = bufs->head; ci; ci = ci->next) {
buf = &ci->buf;
ptr = nghttp2_cpymem(ptr, buf->pos, nghttp2_buf_len(buf));
len += nghttp2_buf_len(buf);
}
df->datamark = df->data;
df->datalimit = df->data+data_length;
df->feedseq[0] = data_length;
df->datalimit = df->data + len;
df->feedseq[0] = len;
}
static ssize_t null_send_callback(nghttp2_session *session,
@ -346,7 +359,7 @@ void test_nghttp2_session_recv(void)
const nghttp2_nv nv[] = {
MAKE_NV("url", "/")
};
nghttp2_buf buf;
nghttp2_bufs bufs;
ssize_t framelen;
nghttp2_frame frame;
ssize_t i;
@ -354,8 +367,9 @@ void test_nghttp2_session_recv(void)
nghttp2_nv *nva;
ssize_t nvlen;
nghttp2_hd_deflater deflater;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
@ -370,12 +384,16 @@ void test_nghttp2_session_recv(void)
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
scripted_data_feed_init2(&df, &bufs);
framelen = nghttp2_bufs_len(&bufs);
/* Send 1 byte per each read */
for(i = 0; i < nghttp2_buf_len(&buf); ++i) {
for(i = 0; i < framelen; ++i) {
df.feedseq[i] = 1;
}
@ -387,17 +405,20 @@ void test_nghttp2_session_recv(void)
}
CU_ASSERT(1 == user_data.frame_recv_cb_called);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Received HEADERS without header block, which is valid */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
5, NGHTTP2_PRI_DEFAULT, NULL, 0);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(0 == rv);
nghttp2_frame_headers_free(&frame.headers);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init2(&df, &bufs);
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.frame_recv_cb_called);
@ -407,21 +428,25 @@ void test_nghttp2_session_recv(void)
/* Some tests for frame too large */
nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
/* Receive PING with too large payload */
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
framelen = nghttp2_frame_pack_ping(&buf, &frame.ping);
rv = nghttp2_frame_pack_ping(&bufs, &frame.ping);
CU_ASSERT(0 == rv);
/* Add extra 16 bytes */
nghttp2_buf_pos_reserve(&buf, nghttp2_buf_len(&buf) + 16);
buf.last += 16;
nghttp2_put_uint16be(buf.pos, frame.hd.length + 16);
nghttp2_bufs_seek_last_present(&bufs);
assert(nghttp2_buf_len(&bufs.cur->buf) >= 16);
bufs.cur->buf.last += 16;
nghttp2_put_uint16be(bufs.cur->buf.pos, frame.hd.length + 16);
nghttp2_frame_ping_free(&frame.ping);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init2(&df, &bufs);
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == user_data.frame_recv_cb_called);
@ -430,7 +455,7 @@ void test_nghttp2_session_recv(void)
CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == OB_CTRL(item)->goaway.error_code);
CU_ASSERT(0 == nghttp2_session_send(session));
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_session_del(session);
}
@ -440,12 +465,12 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
nghttp2_session_callbacks callbacks;
scripted_data_feed df;
my_user_data user_data;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
nghttp2_frame frame;
nghttp2_hd_deflater deflater;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
@ -458,17 +483,18 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
NGHTTP2_PRI_DEFAULT, NULL, 0);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init2(&df, &bufs);
nghttp2_frame_headers_free(&frame.headers);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -482,14 +508,14 @@ void test_nghttp2_session_recv_invalid_frame(void)
const nghttp2_nv nv[] = {
MAKE_NV("url", "/")
};
nghttp2_buf buf;
ssize_t framelen;
nghttp2_bufs bufs;
nghttp2_frame frame;
nghttp2_nv *nva;
ssize_t nvlen;
nghttp2_hd_deflater deflater;
int rv;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
@ -503,11 +529,12 @@ void test_nghttp2_session_recv_invalid_frame(void)
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init2(&df, &bufs);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
@ -515,13 +542,13 @@ void test_nghttp2_session_recv_invalid_frame(void)
/* Receive exactly same bytes of HEADERS is treated as subsequent
HEADERS (e.g., trailers */
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init2(&df, &bufs);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(0 == user_data.frame_send_cb_called);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_hd_deflate_free(&deflater);
@ -680,7 +707,8 @@ void test_nghttp2_session_recv_continuation(void)
nghttp2_nv *nva;
size_t nvlen;
nghttp2_frame frame;
nghttp2_buf buf;
nghttp2_bufs bufs;
nghttp2_buf *buf;
ssize_t rv;
my_user_data ud;
nghttp2_hd_deflater deflater;
@ -688,7 +716,7 @@ void test_nghttp2_session_recv_continuation(void)
size_t datalen;
nghttp2_frame_hd cont_hd;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_header_callback = on_header_callback;
@ -702,16 +730,21 @@ void test_nghttp2_session_recv_continuation(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
/* make sure that all data is in the first buf */
buf = &bufs.head->buf;
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
nghttp2_frame_headers_free(&frame.headers);
/* HEADERS's payload is 1 byte */
memcpy(data, buf.pos, 9);
memcpy(data, buf->pos, 9);
datalen = 9;
buf.pos += 9;
buf->pos += 9;
nghttp2_put_uint16be(data, 1);
@ -724,23 +757,23 @@ void test_nghttp2_session_recv_continuation(void)
nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
datalen += NGHTTP2_FRAME_HDLEN;
memcpy(data + datalen, buf.pos, cont_hd.length);
memcpy(data + datalen, buf->pos, cont_hd.length);
datalen += cont_hd.length;
buf.pos += cont_hd.length;
buf->pos += cont_hd.length;
/* Second CONTINUATION, rest of the bytes */
cont_hd.length = nghttp2_buf_len(&buf);
cont_hd.length = nghttp2_buf_len(buf);
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
cont_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
datalen += NGHTTP2_FRAME_HDLEN;
memcpy(data + datalen, buf.pos, cont_hd.length);
memcpy(data + datalen, buf->pos, cont_hd.length);
datalen += cont_hd.length;
buf.pos += cont_hd.length;
buf->pos += cont_hd.length;
CU_ASSERT(0 == nghttp2_buf_len(&buf));
CU_ASSERT(0 == nghttp2_buf_len(buf));
ud.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, datalen);
@ -759,25 +792,32 @@ void test_nghttp2_session_recv_continuation(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
nghttp2_buf_reset(&buf);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
nghttp2_bufs_reset(&bufs);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
nghttp2_frame_headers_free(&frame.headers);
memcpy(data, buf.pos, nghttp2_buf_len(&buf));
datalen = nghttp2_buf_len(&buf);
/* make sure that all data is in the first buf */
buf = &bufs.head->buf;
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
memcpy(data, buf->pos, nghttp2_buf_len(buf));
datalen = nghttp2_buf_len(buf);
/* Followed by PRIORITY */
nghttp2_frame_priority_init(&frame.priority, 1, 0);
nghttp2_buf_reset(&buf);
nghttp2_bufs_reset(&bufs);
rv = nghttp2_frame_pack_priority(&buf, &frame.priority);
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
memcpy(data + datalen, buf.pos, nghttp2_buf_len(&buf));
datalen += nghttp2_buf_len(&buf);
memcpy(data + datalen, buf->pos, nghttp2_buf_len(buf));
datalen += nghttp2_buf_len(buf);
ud.begin_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, datalen);
@ -787,7 +827,7 @@ void test_nghttp2_session_recv_continuation(void)
CU_ASSERT(NGHTTP2_GOAWAY ==
OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session)));
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -803,13 +843,14 @@ void test_nghttp2_session_recv_premature_headers(void)
nghttp2_nv *nva;
size_t nvlen;
nghttp2_frame frame;
nghttp2_buf buf;
nghttp2_bufs bufs;
nghttp2_buf *buf;
ssize_t rv;
my_user_data ud;
nghttp2_hd_deflater deflater;
nghttp2_outbound_item *item;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
@ -820,24 +861,28 @@ void test_nghttp2_session_recv_premature_headers(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
nghttp2_frame_headers_free(&frame.headers);
/* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint16be(buf.pos, frame.hd.length - 1);
rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf) - 1);
buf = &bufs.head->buf;
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
CU_ASSERT((ssize_t)(nghttp2_buf_len(&buf) - 1) == rv);
/* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint16be(buf->pos, frame.hd.length - 1);
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf) - 1);
CU_ASSERT((ssize_t)(nghttp2_buf_len(buf) - 1) == rv);
item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == OB_CTRL(item)->goaway.error_code);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -855,7 +900,8 @@ void test_nghttp2_session_continue(void)
MAKE_NV("user-agent", "nghttp2/1.0.0"),
MAKE_NV("alpha", "bravo")
};
nghttp2_buf buf;
nghttp2_bufs bufs;
nghttp2_buf *buf;
size_t framelen1, framelen2;
ssize_t rv;
uint8_t buffer[4096];
@ -867,7 +913,7 @@ void test_nghttp2_session_continue(void)
nghttp2_frame_hd data_hd;
nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
frame_pack_bufs_init(&bufs);
nghttp2_buf_wrap_init(&databuf, buffer, sizeof(buffer));
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
@ -885,27 +931,34 @@ void test_nghttp2_session_continue(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
nghttp2_frame_headers_free(&frame.headers);
framelen1 = nghttp2_buf_len(&buf);
databuf.last = nghttp2_cpymem(databuf.last, buf.pos, nghttp2_buf_len(&buf));
buf = &bufs.head->buf;
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
framelen1 = nghttp2_buf_len(buf);
databuf.last = nghttp2_cpymem(databuf.last, buf->pos, nghttp2_buf_len(buf));
nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
3, NGHTTP2_PRI_DEFAULT, nva, nvlen);
nghttp2_buf_reset(&buf);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
nghttp2_bufs_reset(&bufs);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
nghttp2_frame_headers_free(&frame.headers);
framelen2 = nghttp2_buf_len(&buf);
databuf.last = nghttp2_cpymem(databuf.last, buf.pos, nghttp2_buf_len(&buf));
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
framelen2 = nghttp2_buf_len(buf);
databuf.last = nghttp2_cpymem(databuf.last, buf->pos, nghttp2_buf_len(buf));
/* Receive 1st HEADERS and pause */
user_data.begin_headers_cb_called = 0;
@ -1020,7 +1073,7 @@ void test_nghttp2_session_continue(void)
CU_ASSERT(0 == rv);
CU_ASSERT(1 == user_data.frame_recv_cb_called);
nghttp2_buf_free(&buf);
nghttp2_bufs_free(&bufs);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -2266,7 +2319,8 @@ void test_nghttp2_submit_data(void)
nghttp2_private_data *data_frame;
nghttp2_frame_hd hd;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
nghttp2_bufs *framebufs;
nghttp2_buf *buf;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = block_count_send_callback;
@ -2275,7 +2329,7 @@ void test_nghttp2_submit_data(void)
ud.data_source_length = NGHTTP2_DATA_PAYLOAD_LENGTH * 2;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
aob = &session->aob;
framebuf = &aob->framebuf;
framebufs = &aob->framebufs;
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
@ -2287,7 +2341,9 @@ void test_nghttp2_submit_data(void)
ud.block_count = 0;
CU_ASSERT(0 == nghttp2_session_send(session));
data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
buf = &framebufs->head->buf;
nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
/* frame->hd.flags has these flags */
@ -2297,7 +2353,7 @@ void test_nghttp2_submit_data(void)
ud.block_count = 1;
CU_ASSERT(0 == nghttp2_session_send(session));
data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
/* This is the last frame, so we must have following flags */
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) == hd.flags);
@ -2349,6 +2405,9 @@ void test_nghttp2_submit_request_without_data(void)
nghttp2_frame frame;
nghttp2_hd_inflater inflater;
nva_out out;
nghttp2_bufs bufs;
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
acc.length = 0;
@ -2367,12 +2426,14 @@ void test_nghttp2_submit_request_without_data(void)
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
inflate_hd(&inflater, &out, acc.buf + 8, acc.length - 8);
nghttp2_bufs_add(&bufs, acc.buf, acc.length);
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
CU_ASSERT(nvnameeq(":version", &out.nva[0]));
nghttp2_frame_headers_free(&frame.headers);
nva_out_reset(&out);
nghttp2_bufs_free(&bufs);
nghttp2_hd_inflate_free(&inflater);
nghttp2_session_del(session);
}
@ -2421,6 +2482,9 @@ void test_nghttp2_submit_response_without_data(void)
nghttp2_frame frame;
nghttp2_hd_inflater inflater;
nva_out out;
nghttp2_bufs bufs;
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
acc.length = 0;
@ -2442,11 +2506,13 @@ void test_nghttp2_submit_response_without_data(void)
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
inflate_hd(&inflater, &out, acc.buf + 8, acc.length - 8);
nghttp2_bufs_add(&bufs, acc.buf, acc.length);
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
CU_ASSERT(nvnameeq(":version", &out.nva[0]));
nva_out_reset(&out);
nghttp2_bufs_free(&bufs);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_hd_inflate_free(&inflater);
nghttp2_session_del(session);
@ -2591,6 +2657,9 @@ void test_nghttp2_submit_headers(void)
nghttp2_frame frame;
nghttp2_hd_inflater inflater;
nva_out out;
nghttp2_bufs bufs;
frame_pack_bufs_init(&bufs);
nva_out_init(&out);
acc.length = 0;
@ -2633,11 +2702,13 @@ void test_nghttp2_submit_headers(void)
CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
inflate_hd(&inflater, &out, acc.buf + 8, acc.length - 8);
nghttp2_bufs_add(&bufs, acc.buf, acc.length);
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
CU_ASSERT(nvnameeq(":version", &out.nva[0]));
nva_out_reset(&out);
nghttp2_bufs_free(&bufs);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_hd_inflate_free(&inflater);
@ -4066,13 +4137,14 @@ void test_nghttp2_session_data_backoff_by_high_pri_frame(void)
nghttp2_session_del(session);
}
static void check_session_recv_data_with_padding(const uint8_t *in,
size_t inlen,
static void check_session_recv_data_with_padding(nghttp2_bufs *bufs,
size_t datalen)
{
nghttp2_session *session;
my_user_data ud;
nghttp2_session_callbacks callbacks;
uint8_t *in;
size_t inlen;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.on_frame_recv_callback = on_frame_recv_callback;
@ -4083,13 +4155,17 @@ static void check_session_recv_data_with_padding(const uint8_t *in,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
NULL);
inlen = nghttp2_bufs_remove(bufs, &in);
ud.frame_recv_cb_called = 0;
ud.data_chunk_len = 0;
CU_ASSERT((ssize_t)inlen == nghttp2_session_mem_recv(session, in, inlen));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(datalen == ud.data_chunk_len);
free(in);
nghttp2_session_del(session);
}
@ -4124,14 +4200,12 @@ void test_nghttp2_session_pack_data_with_padding(void)
frame = OB_DATA(session->aob.item);
CU_ASSERT(ud.padding_boundary - datalen == frame->padlen);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH);
/* We no longer set PAD_HIGH and PAD_LOW flags in frame->hd */
/* CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); */
/* CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH); */
/* Check reception of this DATA frame */
check_session_recv_data_with_padding
(session->aob.framebuf.pos,
session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen);
check_session_recv_data_with_padding(&session->aob.framebufs, datalen);
nghttp2_session_del(session);
@ -4150,14 +4224,12 @@ void test_nghttp2_session_pack_data_with_padding(void)
frame = OB_DATA(session->aob.item);
CU_ASSERT((frame->padlen + datalen) % ud.padding_boundary == 0);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
/* We no longer set PAD_HIGH and PAD_LOW flags in frame->hd */
/* CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); */
CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH));
/* Check reception of this DATA frame */
check_session_recv_data_with_padding
(session->aob.framebuf.pos,
session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen);
check_session_recv_data_with_padding(&session->aob.framebufs, datalen);
nghttp2_session_del(session);
}

View File

@ -28,8 +28,15 @@
#include <CUnit/CUnit.h>
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf)
#include "nghttp2_helper.h"
int unpack_framebuf(nghttp2_frame *frame, nghttp2_bufs *bufs)
{
nghttp2_buf *buf;
/* Assuming we have required data in first buffer. We don't decode
header block so, we don't mind its space */
buf = &bufs->head->buf;
return unpack_frame(frame, buf->pos, nghttp2_buf_len(buf));
}
@ -143,28 +150,66 @@ void add_out(nva_out *out, nghttp2_nv *nv)
}
ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
uint8_t *buf, size_t buflen)
nghttp2_bufs *bufs, size_t offset)
{
ssize_t rv;
nghttp2_nv nv;
int inflate_flags;
size_t initial = buflen;
nghttp2_buf_chain *ci;
nghttp2_buf *buf;
nghttp2_buf bp;
int final;
size_t processed;
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, buf, buflen, 1);
if(rv < 0) {
return rv;
processed = 0;
for(ci = bufs->head; ci; ci = ci->next) {
buf = &ci->buf;
final = nghttp2_buf_len(buf) == 0 || ci->next == NULL;
bp = *buf;
if(offset) {
int n;
n = nghttp2_min((ssize_t)offset, nghttp2_buf_len(&bp));
bp.pos += n;
offset -= n;
}
buf += rv;
buflen -= rv;
if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
add_out(out, &nv);
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
break;
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags,
bp.pos, nghttp2_buf_len(&bp), final);
if(rv < 0) {
return rv;
}
bp.pos += rv;
processed += rv;
if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
add_out(out, &nv);
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
break;
}
}
}
nghttp2_hd_inflate_end_headers(inflater);
return initial - buflen;
return processed;
}
void frame_pack_bufs_init(nghttp2_bufs *bufs)
{
/* 2 for PAD_HIGH and PAD_LOW */
nghttp2_bufs_init2(bufs, 4096, 16, NGHTTP2_FRAME_HDLEN + 2);
}
void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size)
{
/* 2 for PAD_HIGH and PAD_LOW */
nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 2);
}

View File

@ -54,7 +54,7 @@
free(a); \
} while(0);
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf);
int unpack_framebuf(nghttp2_frame *frame, nghttp2_bufs *bufs);
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len);
@ -75,6 +75,10 @@ void nva_out_reset(nva_out *out);
void add_out(nva_out *out, nghttp2_nv *nv);
ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
uint8_t *buf, size_t buflen);
nghttp2_bufs *bufs, size_t offset);
void frame_pack_bufs_init(nghttp2_bufs *bufs);
void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size);
#endif /* NGHTTP2_TEST_HELPER_H */