Introduce nghttp2_buf to ease buffer management

This commit is contained in:
Tatsuhiro Tsujikawa 2014-03-11 01:47:38 +09:00
parent d074cb611f
commit 358b4386d3
21 changed files with 1604 additions and 894 deletions

View File

@ -33,6 +33,7 @@ lib_LTLIBRARIES = libnghttp2.la
OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_buffer.c nghttp2_frame.c \
nghttp2_buf.c \
nghttp2_stream.c nghttp2_outbound_item.c \
nghttp2_session.c nghttp2_submit.c \
nghttp2_helper.c \
@ -42,6 +43,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_buffer.h nghttp2_frame.h \
nghttp2_buf.h \
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
nghttp2_npn.h nghttp2_gzip.h \
nghttp2_submit.h nghttp2_outbound_item.h \

95
lib/nghttp2_buf.c Normal file
View File

@ -0,0 +1,95 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_buf.h"
#include "nghttp2_helper.h"
void nghttp2_buf_init(nghttp2_buf *buf)
{
buf->begin = NULL;
buf->end = NULL;
buf->pos = NULL;
buf->last = NULL;
buf->mark = NULL;
}
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
{
nghttp2_buf_init(buf);
return nghttp2_buf_reserve(buf, initial);
}
void nghttp2_buf_free(nghttp2_buf *buf)
{
free(buf->begin);
}
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
{
uint8_t *ptr;
size_t cap;
cap = nghttp2_buf_cap(buf);
if(cap >= new_cap) {
return 0;
}
new_cap = nghttp2_max(new_cap, cap * 2);
ptr = realloc(buf->begin, new_cap);
if(ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
buf->pos = ptr + (buf->pos - buf->begin);
buf->last = ptr + (buf->last - buf->begin);
buf->mark = ptr + (buf->mark - buf->begin);
buf->begin = ptr;
buf->end = ptr + new_cap;
return 0;
}
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_pos_offset(buf) + new_rel_cap);
}
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_last_offset(buf) + new_rel_cap);
}
void nghttp2_buf_reset(nghttp2_buf *buf)
{
buf->pos = buf->last = buf->mark = buf->begin;
}
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len)
{
buf->begin = buf->pos = buf->last = buf->mark = begin;
buf->end = begin + len;
}

137
lib/nghttp2_buf.h Normal file
View File

@ -0,0 +1,137 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_BUF_H
#define NGHTTP2_BUF_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
typedef struct {
/* This points to the beginning of the buffer. The effective range
of buffer is [begin, end). */
uint8_t *begin;
/* This points to the memory one byte beyond the end of the
buffer. */
uint8_t *end;
/* The position indicator for effective start of the buffer. pos <=
last must be hold. */
uint8_t *pos;
/* The position indicator for effective one beyond of the end of the
buffer. last <= end must be hold. */
uint8_t *last;
/* Mark arbitrary position in buffer [begin, end) */
uint8_t *mark;
} nghttp2_buf;
#define nghttp2_buf_len(BUF) ((BUF)->last - (BUF)->pos)
#define nghttp2_buf_avail(BUF) ((BUF)->end - (BUF)->last)
#define nghttp2_buf_cap(BUF) ((BUF)->end - (BUF)->begin)
#define nghttp2_buf_pos_offset(BUF) ((BUF)->pos - (BUF)->begin)
#define nghttp2_buf_last_offset(BUF) ((BUF)->last - (BUF)->begin)
#define nghttp2_buf_shift_right(BUF, AMT) \
do { \
(BUF)->pos += AMT; \
(BUF)->last += AMT; \
} while(0)
#define nghttp2_buf_shift_left(BUF, AMT) \
do { \
(BUF)->pos -= AMT; \
(BUF)->last -= AMT; \
} while(0)
/*
* Initializes the |buf|. No memory is allocated in this function. Use
* nghttp2_buf_reserve() or nghttp2_buf_reserve2() to allocate memory.
*/
void nghttp2_buf_init(nghttp2_buf *buf);
/*
* Initializes the |buf| and allocates at least |initial| bytes of
* memory.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial);
/*
* Frees buffer in |buf|.
*/
void nghttp2_buf_free(nghttp2_buf *buf);
/*
* Extends buffer so that nghttp2_buf_cap() returns at least
* |new_cap|. If extensions took place, buffer pointers in |buf| will
* change.
*
* This function returns 0 if it succeeds, or one of the followings
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_pos_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->pos.
*/
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_last_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->last.
*/
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* Resets pos, last, mark member of |buf| to buf->begin.
*/
void nghttp2_buf_reset(nghttp2_buf *buf);
/*
* Initializes |buf| using supplied buffer |begin| of length
* |len|. Semantically, the application should not call *_reserve() or
* nghttp2_free() functions for |buf|.
*/
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
#endif /* NGHTTP2_BUF_H */

View File

@ -224,50 +224,64 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
}
}
ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater)
{
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2;
size_t nv_offset =
payloadoff + nghttp2_frame_headers_payload_nv_offset(frame);
size_t nv_offset;
ssize_t rv;
size_t payloadlen;
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset,
frame->nva, frame->nvlen);
if(rv < 0) {
return rv;
}
assert(nghttp2_buf_len(buf) == 0);
payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv;
/* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
*bufoff_ptr = 2;
frame->padlen = 0;
frame->hd.length = payloadlen;
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
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_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) {
return rv;
}
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
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);
buf->pos -= nv_offset;
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_HEAD_LENGTH);
/* pack ctrl header after length is determined */
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) {
if(NGHTTP2_MAX_FRAME_LENGTH < frame->hd.length) {
/* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH;
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else {
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd);
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
}
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri);
nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN, frame->pri);
}
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
return nghttp2_buf_len(buf);
}
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
@ -284,19 +298,28 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
return 0;
}
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame)
{
ssize_t framelen= NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri);
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->pri);
buf->last += 4;
return nghttp2_buf_len(buf);
}
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
@ -306,19 +329,28 @@ 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(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->error_code);
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
return nghttp2_buf_len(buf);
}
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
@ -328,19 +360,28 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
frame->error_code = nghttp2_get_uint32(payload);
}
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
nghttp2_frame_pack_settings_payload(*buf_ptr + 8, frame->iv, frame->niv);
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
buf->last += nghttp2_frame_pack_settings_payload(buf->last,
frame->iv, frame->niv);
return nghttp2_buf_len(buf);
}
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
@ -395,47 +436,60 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
return 0;
}
ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater)
{
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2;
size_t nv_offset = payloadoff + 4;
size_t nv_offset = NGHTTP2_FRAME_HDLEN + 4;
ssize_t rv;
size_t payloadlen;
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset,
frame->nva, frame->nvlen);
if(rv < 0) {
return rv;
}
assert(nghttp2_buf_len(buf) == 0);
payloadlen = 4 + rv;
/* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
*bufoff_ptr = 2;
frame->padlen = 0;
frame->hd.length = payloadlen;
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
/* If frame->nvlen == 0, nghttp2_buf_len(buf) may be smaller than
nv_offset */
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) {
return rv;
}
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
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);
buf->pos -= nv_offset;
if(rv < 0) {
return rv;
}
frame->hd.length = 4 + 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_HEAD_LENGTH);
/* pack ctrl header after length is determined */
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) {
if(NGHTTP2_MAX_FRAME_LENGTH < frame->hd.length) {
/* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH;
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else {
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd);
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
}
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->promised_stream_id);
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN,
frame->promised_stream_id);
return nghttp2_buf_len(buf);
}
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
@ -449,19 +503,27 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
return 0;
}
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_ping *frame)
ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 8;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
memcpy(&(*buf_ptr)[8], frame->opaque_data, sizeof(frame->opaque_data));
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
memcpy(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
buf->last += sizeof(frame->opaque_data);
return nghttp2_buf_len(buf);
}
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
@ -471,21 +533,33 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
}
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_goaway *frame)
ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->last_stream_id);
nghttp2_put_uint32be(&(*buf_ptr)[12], frame->error_code);
memcpy(&(*buf_ptr)[16], frame->opaque_data, frame->opaque_data_len);
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->last_stream_id);
buf->last += 4;
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;
return nghttp2_buf_len(buf);
}
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
@ -499,19 +573,28 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
frame->opaque_data_len = 0;
}
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame)
{
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->window_size_increment);
return framelen;
memset(buf->last, 0, framelen);
nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->window_size_increment);
buf->last += 4;
return nghttp2_buf_len(buf);
}
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
@ -654,42 +737,34 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
return 1;
}
int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr,
uint8_t *flags_ptr,
size_t payloadlen,
size_t padlen)
void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr, size_t padlen)
{
int rv;
size_t trail_padlen = 0;
/* extra 2 bytes for PAD_HIGH and PAD_LOW. */
size_t trail_padoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen;
if(padlen > 257) {
if(padlen > 256) {
uint8_t *p;
*bufoff_ptr -= 2;
trail_padlen = padlen - 2;
*flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
p = *buf_ptr + *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH;
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_HEAD_LENGTH;
*p++ = trail_padlen >> 8;
*p = trail_padlen & 0xff;
} else if(padlen > 0) {
--*bufoff_ptr;
assert(nghttp2_buf_pos_offset(buf) >= 1);
/* Consume previous 1 byte, shifting 1 bytes to the left */
nghttp2_buf_shift_left(buf, 1);
trail_padlen = padlen - 1;
*flags_ptr |= NGHTTP2_FLAG_PAD_LOW;
(*buf_ptr)[*bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen;
} else {
return 0;
}
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr,
trail_padoff + trail_padlen);
if(rv != 0) {
return rv;
*(buf->pos + NGHTTP2_FRAME_HEAD_LENGTH) = trail_padlen;
}
/* We have to zero out padding bytes so that we won't reveal the
possible internal data to the remote peer */
memset((*buf_ptr) + trail_padoff, 0, trail_padlen);
return 0;
}

View File

@ -32,6 +32,7 @@
#include <nghttp2/nghttp2.h>
#include "nghttp2_hd.h"
#include "nghttp2_buffer.h"
#include "nghttp2_buf.h"
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
@ -39,7 +40,8 @@
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The maximum payload length of a frame */
/* The maximum payload length of a frame TODO: Must be renamed as
NGHTTP2_MAX_PAYLOAD_LENGTH */
#define NGHTTP2_MAX_FRAME_LENGTH ((1 << 14) - 1)
/* The maximum length of DATA frame payload. To fit entire DATA frame
@ -48,7 +50,8 @@
#define NGHTTP2_DATA_PAYLOAD_LENGTH 4086
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HEAD_LENGTH 8
#define NGHTTP2_FRAME_HDLEN 8
#define NGHTTP2_FRAME_HEAD_LENGTH NGHTTP2_FRAME_HDLEN
/* The number of bytes for each SETTINGS entry */
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5
@ -100,15 +103,12 @@ 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_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes.
* This function expands |*buf_ptr| as necessary to store frame. When
* expansion occurred, memory previously pointed by |*buf_ptr| may
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
* 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.
*
* The first byte the frame is serialized is returned in the
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
* The first byte the frame is serialized is returned in the |buf|.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
@ -116,8 +116,8 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
*
* This function returns the size of packed frame (which includes
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the
* This function returns the size of packed frame (which equals to
* nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
@ -127,9 +127,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
@ -149,9 +147,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
/*
* Packs PRIORITY frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
@ -159,7 +156,7 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame);
/*
@ -171,10 +168,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
/*
* Packs RST_STREAM frame |frame| in wire frame format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|. In spdy/2 spec, RST_STREAM wire format is always 16
* bytes long.
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
@ -182,7 +177,7 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame);
/*
@ -194,9 +189,8 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
/*
* Packs SETTINGS frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
@ -204,7 +198,7 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame);
/*
@ -253,14 +247,11 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
/*
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes.
* This function expands |*buf_ptr| as necessary to store frame. When
* expansion occurred, memory previously pointed by |*buf_ptr| may
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
* |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.
*
* The first byte the frame is serialized is returned in the
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
* The first byte the frame is serialized is returned in the |buf|.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
@ -268,13 +259,10 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
*
* This function returns the size of packed frame (which includes
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the
* This function returns the size of packed frame (which equals to
* nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* following negative error codes:
*
* This function returns the size of packed frame 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
@ -282,9 +270,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *bufoff_ptr,
ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater);
@ -303,10 +289,8 @@ 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_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* Packs PING frame |frame| in wire format and store it in |buf|. This
* function expands |buf| as necessary to store given |frame|.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
@ -314,8 +298,7 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_ping *frame);
ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame);
/*
* Unpacks PING wire format into |frame|.
@ -326,9 +309,8 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
/*
* Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* |buf|. This function expands |buf| as necessary to store given
* |frame|.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
@ -336,8 +318,7 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_goaway *frame);
ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame);
/*
* Unpacks GOAWAY wire format into |frame|.
@ -348,9 +329,8 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
/*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* in |buf|. This function expands |buf| as necessary to store given
* |frame|.
*
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
@ -358,7 +338,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr,
ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame);
/*
@ -508,29 +488,22 @@ void nghttp2_nv_array_del(nghttp2_nv *nva);
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
/*
* Add padding to the payload in the |*buf_ptr| of length
* |*buflen_ptr|. The payload length is given in |payloadlen|. The
* frame header starts at offset |*bufoff_ptr|. Therefore, the payload
* must start at offset *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH from
* |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The padding is
* 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|.
*
* The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and
* NGHTTP2_FLAG_PAD_HIGH based on the padding length. The
* |*bufoff_ptr| will have the offset starting the frame header in
* |*buf_ptr|.
* NGHTTP2_FLAG_PAD_HIGH based on the padding length.
*
* The |*buf_ptr| and |*buflen_ptr| may be extended to include padding
* bytes.
* 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 allocate
* buffer size as if these 2 bytes always exist. Depending of the
* length of the padding, we move the location of frame header and
* adjust |*bufoff_ptr|. If more than or equal to 256 padding is made,
* the |*bufoff_ptr| is 0 and the content of the |*buf_ptr| looks like
* this:
* 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
@ -543,8 +516,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* +---------------+---------------+-------------------------------+
*
*
* If padding is less than 256 but strictly more than 0, the
* |*bufoff_ptr| is 1 and the |*buf_ptr| looks like this:
* 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
@ -556,8 +529,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* . Frame Header | Pad low | Payload ...
* +---------------+---------------+-------------------------------+
*
* If no padding is added, the |*bufoff_ptr| is 2 and the |*buf_ptr|
* looks like this:
* 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
@ -571,17 +544,10 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
*
* 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_ptr| is large
* enough to account the additional padding, of course).
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* additional copy operation is required (if the |buf| is large enough
* to account the additional padding, of course).
*/
int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr, uint8_t *flags_ptr,
size_t payloadlen, size_t padlen);
void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr,
size_t padlen);
#endif /* NGHTTP2_FRAME_H */

View File

@ -436,17 +436,21 @@ static int emit_indname_header(nghttp2_nv *nv_out, nghttp2_hd_entry *ent,
return 0;
}
static int ensure_write_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t offset, size_t need)
static int ensure_write_buffer(nghttp2_buf *buf, size_t need)
{
int rv;
if(need + offset > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
need += nghttp2_buf_last_offset(buf);
if(need > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
return NGHTTP2_ERR_HEADER_COMP;
}
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
rv = nghttp2_buf_reserve(buf, need);
if(rv != 0) {
return NGHTTP2_ERR_NOMEM;
}
return 0;
}
@ -556,55 +560,68 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
return in + 1;
}
static int emit_clear_refset(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr)
static int emit_clear_refset(nghttp2_buf *buf)
{
int rv;
uint8_t *bufp;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 2);
rv = ensure_write_buffer(buf, 2);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = 0x80u;
*bufp = 0x80u;
*offset_ptr += 2;
*bufp++ = 0x80u;
buf->last = bufp;
return 0;
}
static int emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size)
static int emit_table_size(nghttp2_buf *buf, size_t table_size)
{
int rv;
uint8_t *bufp;
size_t blocklen = 1 + count_encoded_length(table_size, 7);
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
size_t blocklen;
blocklen = 1 + count_encoded_length(table_size, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
}
DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size));
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = 0x80u;
*bufp = 0;
encode_length(bufp, table_size, 7);
*offset_ptr += blocklen;
buf->last += blocklen;
return 0;
}
static int emit_indexed_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index)
static int emit_indexed_block(nghttp2_buf *buf, size_t index)
{
int rv;
uint8_t *bufp;
size_t blocklen = count_encoded_length(index + 1, 7);
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
size_t blocklen;
blocklen = count_encoded_length(index + 1, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
*bufp = 0x80u;
encode_length(bufp, index + 1, 7);
*offset_ptr += blocklen;
*buf->last = 0x80u;
encode_length(buf->last, index + 1, 7);
buf->last += blocklen;
return 0;
}
@ -613,6 +630,7 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
const uint8_t *str, size_t len)
{
size_t rv;
*buf = huffman ? 1 << 7 : 0;
rv = encode_length(buf, enclen, 7);
buf += rv;
@ -625,66 +643,89 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
return rv + enclen;
}
static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
static int emit_indname_block(nghttp2_buf *buf, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing)
{
int rv;
uint8_t *bufp;
size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
size_t blocklen = count_encoded_length(index + 1, 6);
int huffman = encvallen < valuelen;
size_t encvallen;
size_t blocklen;
int huffman;
encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
blocklen = count_encoded_length(index + 1, 6);
huffman = encvallen < valuelen;
if(!huffman) {
encvallen = valuelen;
}
blocklen += count_encoded_length(encvallen, 7) + encvallen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, index + 1, 6);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
bufp += emit_string(bufp, buf->end - bufp,
encvallen, huffman, value, valuelen);
assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen);
*offset_ptr += blocklen;
assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
return 0;
}
static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
static int emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
int inc_indexing)
{
int rv;
uint8_t *bufp;
size_t encnamelen =
nghttp2_hd_huff_encode_count(nv->name, nv->namelen);
size_t encvallen =
nghttp2_hd_huff_encode_count(nv->value, nv->valuelen);
size_t blocklen = 1;
int name_huffman = encnamelen < nv->namelen;
int value_huffman = encvallen < nv->valuelen;
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;
if(!name_huffman) {
encnamelen = nv->namelen;
}
if(!value_huffman) {
encvallen = nv->valuelen;
}
blocklen += count_encoded_length(encnamelen, 7) + encnamelen +
count_encoded_length(encvallen, 7) + encvallen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) {
return rv;
}
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = inc_indexing ? 0 : 0x40u;
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
bufp += emit_string(bufp, buf->end - bufp,
encnamelen, name_huffman, nv->name, nv->namelen);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr),
bufp += emit_string(bufp, buf->end - bufp,
encvallen, value_huffman, nv->value, nv->valuelen);
*offset_ptr += blocklen;
assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
return 0;
}
@ -692,15 +733,12 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
* Emit common header with |index| by toggle off and on (thus 2
* indexed representation emissions).
*/
static int emit_implicit(uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *offset_ptr,
size_t index)
static int emit_implicit(nghttp2_buf *buf, size_t index)
{
int i;
int rv;
int i, rv;
for(i = 0; i < 2; ++i) {
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, index);
if(rv != 0) {
return rv;
}
@ -709,26 +747,29 @@ static int emit_implicit(uint8_t **buf_ptr,
}
static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *offset_ptr,
nghttp2_buf *buf,
nghttp2_nv *nv,
uint8_t entry_flags)
{
int rv;
nghttp2_hd_entry *new_ent;
size_t room = entry_room(nv->namelen, nv->valuelen);
size_t room;
room = entry_room(nv->namelen, nv->valuelen);
while(context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
context->hd_table.len > 0) {
size_t index = context->hd_table.len - 1;
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
/* 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_ptr, buflen_ptr, offset_ptr, index);
rv = emit_implicit(buf, index);
if(rv != 0) {
return NULL;
}
@ -948,24 +989,25 @@ static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
}
static int deflate_nv(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr,
nghttp2_nv *nv)
nghttp2_buf *buf, nghttp2_nv *nv)
{
int rv;
nghttp2_hd_entry *ent;
search_result res;
res = search_hd_table(&deflater->ctx, nv);
if(res.index != -1 && res.name_value_match) {
size_t index = res.index;
ent = nghttp2_hd_table_get(&deflater->ctx, index);
if(index >= deflater->ctx.hd_table.len) {
nghttp2_hd_entry *new_ent;
/* 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_ptr, buflen_ptr,
offset_ptr, &ent->nv,
new_ent = add_hd_table_incremental(&deflater->ctx, buf, &ent->nv,
NGHTTP2_HD_FLAG_NONE);
if(!new_ent) {
return NGHTTP2_ERR_HEADER_COMP;
@ -979,13 +1021,13 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
set */
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
}
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, 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_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, index);
if(rv != 0) {
return rv;
}
@ -1015,7 +1057,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_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, index);
if(rv != 0) {
break;
}
@ -1033,12 +1075,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_ptr, buflen_ptr,
offset_ptr, &nv_indname,
new_ent = add_hd_table_incremental(&deflater->ctx, buf, &nv_indname,
NGHTTP2_HD_FLAG_VALUE_ALLOC);
} else {
new_ent = add_hd_table_incremental(&deflater->ctx, buf_ptr, buflen_ptr,
offset_ptr, nv,
new_ent = add_hd_table_incremental(&deflater->ctx, buf, nv,
NGHTTP2_HD_FLAG_NAME_ALLOC |
NGHTTP2_HD_FLAG_VALUE_ALLOC);
}
@ -1056,10 +1096,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
incidx = 1;
}
if(index == -1) {
rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx);
rv = emit_newname_block(buf, nv, incidx);
} else {
rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index,
nv->value, nv->valuelen, incidx);
rv = emit_indname_block(buf, index, nv->value, nv->valuelen, incidx);
}
if(rv != 0) {
return rv;
@ -1070,42 +1109,44 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
size_t index,
uint8_t **buf_ptr,
size_t *buflen_ptr,
size_t *offset_ptr)
nghttp2_buf *buf)
{
int rv;
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) &&
(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) == 0 &&
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
/* This entry is not present in the current header set and must
be removed. */
ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, index);
if(rv != 0) {
return rv;
}
}
ent->flags &= ~(NGHTTP2_HD_FLAG_EMIT | NGHTTP2_HD_FLAG_IMPLICIT_EMIT);
return 0;
}
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t nv_offset,
nghttp2_buf *buf,
nghttp2_nv *nv, size_t nvlen)
{
size_t i, offset;
size_t i;
int rv = 0;
assert(nghttp2_buf_len(buf) == 0);
if(deflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP;
}
offset = nv_offset;
if(deflater->ctx.hd_table_bufsize_max >
deflater->deflate_hd_table_bufsize_max) {
rv = emit_table_size(buf_ptr, buflen_ptr, &offset,
deflater->deflate_hd_table_bufsize_max);
rv = emit_table_size(buf, deflater->deflate_hd_table_bufsize_max);
if(rv != 0) {
goto fail;
}
@ -1114,26 +1155,28 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
}
if(deflater->no_refset) {
rv = emit_clear_refset(buf_ptr, buflen_ptr, &offset);
rv = emit_clear_refset(buf);
if(rv != 0) {
goto fail;
}
clear_refset(&deflater->ctx);
}
for(i = 0; i < nvlen; ++i) {
rv = deflate_nv(deflater, buf_ptr, buflen_ptr, &offset, &nv[i]);
rv = deflate_nv(deflater, buf, &nv[i]);
if(rv != 0) {
goto fail;
}
}
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_ptr, buflen_ptr, &offset);
rv = deflate_post_process_hd_entry(ent, i, buf);
if(rv != 0) {
goto fail;
}
}
return offset - nv_offset;
return nghttp2_buf_len(buf);
fail:
deflater->ctx.bad = 1;
return rv;
@ -1259,8 +1302,8 @@ static int hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
if(inflater->index >= inflater->ctx.hd_table.len) {
nghttp2_hd_entry *new_ent;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL,
&ent->nv, NGHTTP2_HD_FLAG_NONE);
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &ent->nv,
NGHTTP2_HD_FLAG_NONE);
if(!new_ent) {
return NGHTTP2_ERR_NOMEM;
}
@ -1307,8 +1350,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
uint8_t ent_flags =
NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC |
NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL, &nv,
ent_flags);
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &nv, ent_flags);
if(new_ent) {
nghttp2_buffer_release(&inflater->namebuf);
nghttp2_buffer_release(&inflater->valuebuf);
@ -1357,10 +1399,8 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
nv.namelen = inflater->ent_name->nv.namelen;
nv.value = inflater->valuebuf.buf;
nv.valuelen = inflater->valuebuf.len;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL, &nv,
ent_flags);
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &nv, ent_flags);
if(!static_name && --inflater->ent_name->ref == 0) {
fprintf(stderr, "index=%zu, len=%zu\n", inflater->index, inflater->ctx.hd_table.len);
nghttp2_hd_entry_free(inflater->ent_name);
free(inflater->ent_name);
}
@ -1693,24 +1733,20 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater)
return 0;
}
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing)
{
return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr,
index, value, valuelen, inc_indexing);
return emit_indname_block(buf, index, value, valuelen, inc_indexing);
}
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
int inc_indexing)
{
return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing);
return emit_newname_block(buf, nv, inc_indexing);
}
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size)
int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size)
{
return emit_table_size(buf_ptr, buflen_ptr, offset_ptr, table_size);
return emit_table_size(buf, table_size);
}

View File

@ -33,6 +33,7 @@
#include "nghttp2_hd_huffman.h"
#include "nghttp2_buffer.h"
#include "nghttp2_buf.h"
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE (1 << 12)
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
@ -295,16 +296,13 @@ 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_ptr| with the length |*buflen_ptr|.
* The output starts after |nv_offset| bytes from |*buf_ptr|.
* the buffer pointed by the |buf|. The caller must ensure that
* nghttp2_buf_len(buf) == 0 holds. Write starts at buf->last.
*
* This function expands |*buf_ptr| as necessary to store the
* result. When expansion occurred, memory previously pointed by
* |*buf_ptr| may change. |*buf_ptr| and |*buflen_ptr| are updated
* accordingly.
* This function expands |buf| as necessary to store the result.
*
* This function copies necessary data into |*buf_ptr|. After this
* function returns, it is safe to delete the |nva|.
* This function copies necessary data into |buf|. 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
@ -319,8 +317,7 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
* Deflation process has failed.
*/
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t nv_offset,
nghttp2_buf *buf,
nghttp2_nv *nva, size_t nvlen);
typedef enum {
@ -373,19 +370,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(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t index,
int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
const uint8_t *value, size_t valuelen,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, size_t table_size);
int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size);
/* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,

View File

@ -382,3 +382,10 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len)
}
return 1;
}
uint8_t* nghttp2_cpymem(uint8_t *dest, uint8_t *src, size_t len)
{
memcpy(dest, src, len);
return dest + len;
}

View File

@ -126,4 +126,11 @@ int nghttp2_should_send_window_update(int32_t local_window_size,
*/
void nghttp2_free(void *ptr);
/*
* Copies the buffer |src| of length |len| to the destination pointed
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
* . Returns dest + len.
*/
uint8_t* nghttp2_cpymem(uint8_t *dest, uint8_t *src, size_t len);
#endif /* NGHTTP2_HELPER_H */

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;
aob->framebuflen = aob->framebufoff = aob->framebufmark = 0;
nghttp2_buf_reset(&aob->framebuf);
aob->state = NGHTTP2_OB_POP_ITEM;
}
@ -290,13 +290,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
(*session_ptr)->server = 1;
}
(*session_ptr)->aob.framebuf = malloc
(NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH);
if((*session_ptr)->aob.framebuf == NULL) {
rv = NGHTTP2_ERR_NOMEM;
rv = nghttp2_buf_init2(&(*session_ptr)->aob.framebuf,
NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH);
if(rv != 0) {
goto fail_aob_framebuf;
}
(*session_ptr)->aob.framebufmax = NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH;
nghttp2_active_outbound_item_reset(&(*session_ptr)->aob);
memset((*session_ptr)->remote_settings, 0,
@ -419,7 +418,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);
free(session->aob.framebuf);
nghttp2_buf_free(&session->aob.framebuf);
free(session);
}
@ -1125,6 +1124,36 @@ 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. */
@ -1133,6 +1162,9 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
{
int rv;
ssize_t padded_payloadlen;
nghttp2_active_outbound_item *aob;
aob = &session->aob;
padded_payloadlen = session_call_select_padding(session, frame,
frame->hd.length + 1024);
@ -1143,7 +1175,7 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
frame->headers.padlen = padded_payloadlen - frame->hd.length;
frame->hd.length = padded_payloadlen;
DEBUGF(fprintf(stderr, "payloadlen=%zu, padlen=%zu\n",
DEBUGF(fprintf(stderr, "padding selected: payloadlen=%zu, padlen=%zu\n",
frame->hd.length, frame->headers.padlen));
if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) {
@ -1151,49 +1183,59 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH;
if(NGHTTP2_MAX_FRAME_LENGTH >
frame->hd.length - frame->headers.padlen) {
size_t padlen = NGHTTP2_MAX_FRAME_LENGTH -
if(NGHTTP2_MAX_FRAME_LENGTH > frame->hd.length - frame->headers.padlen) {
size_t padlen;
padlen = NGHTTP2_MAX_FRAME_LENGTH -
(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 = nghttp2_frame_add_pad(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&hd.flags,
hd.length - padlen,
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
(session->aob.framebuf + session->aob.framebufoff, &hd);
/* At this point, framebuflen > session->aob.framebufmax. But
before we access the missing part, we will allocate it in
nghttp2_session_after_frame_sent(). */
nghttp2_frame_pack_frame_hd(aob->framebuf.pos, &hd);
} else if(frame->headers.padlen > 0) {
nghttp2_frame_hd hd = frame->hd;
rv = nghttp2_frame_add_pad(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&hd.flags,
frame->hd.length - frame->headers.padlen,
frame->headers.padlen);
rv = session_reserve_pad_trail(session, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
nghttp2_frame_pack_frame_hd
(session->aob.framebuf + session->aob.framebufoff, &hd);
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);
}
return session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH
+ frame->hd.length;
return nghttp2_buf_len(&session->aob.framebuf);
}
static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
@ -1233,13 +1275,16 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
}
}
framebuflen = nghttp2_frame_pack_headers(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&frame->headers,
&session->hd_deflater);
if(framebuflen < 0) {
return framebuflen;
}
DEBUGF(fprintf(stderr,
"before padding, HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
framebuflen = session_headers_add_pad(session, frame);
if(framebuflen < 0) {
return framebuflen;
@ -1266,6 +1311,10 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
default:
break;
}
DEBUGF(fprintf(stderr, "HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
break;
}
case NGHTTP2_PRIORITY: {
@ -1275,7 +1324,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv;
}
framebuflen = nghttp2_frame_pack_priority(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->priority);
if(framebuflen < 0) {
return framebuflen;
@ -1284,7 +1332,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
}
case NGHTTP2_RST_STREAM:
framebuflen = nghttp2_frame_pack_rst_stream(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->rst_stream);
if(framebuflen < 0) {
return framebuflen;
@ -1296,7 +1343,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv;
}
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->settings);
if(framebuflen < 0) {
return framebuflen;
@ -1316,8 +1362,6 @@ static ssize_t 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,
&session->aob.framebufmax,
&session->aob.framebufoff,
&frame->push_promise,
&session->hd_deflater);
if(framebuflen < 0) {
@ -1343,7 +1387,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
}
case NGHTTP2_PING:
framebuflen = nghttp2_frame_pack_ping(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->ping);
if(framebuflen < 0) {
return framebuflen;
@ -1356,7 +1399,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv;
}
framebuflen = nghttp2_frame_pack_window_update(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->window_update);
if(framebuflen < 0) {
return framebuflen;
@ -1372,7 +1414,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_GOAWAY_ALREADY_SENT;
}
framebuflen = nghttp2_frame_pack_goaway(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->goaway);
if(framebuflen < 0) {
return framebuflen;
@ -1403,8 +1444,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
}
framebuflen = nghttp2_session_pack_data(session,
&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
next_readmax,
data_frame);
if(framebuflen == NGHTTP2_ERR_DEFERRED) {
@ -1516,13 +1555,8 @@ static int session_call_before_frame_send(nghttp2_session *session,
{
int rv;
if(session->callbacks.before_frame_send_callback) {
/* Adjust frame length to deal with CONTINUATION frame */
size_t origlen = frame->hd.length;
frame->hd.length =
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH;
rv = session->callbacks.before_frame_send_callback(session, frame,
session->user_data);
frame->hd.length = origlen;
if(rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@ -1558,24 +1592,33 @@ static int session_call_on_frame_send(nghttp2_session *session,
static int nghttp2_session_after_frame_sent(nghttp2_session *session)
{
int rv;
nghttp2_outbound_item *item = session->aob.item;
nghttp2_active_outbound_item *aob = &session->aob;
nghttp2_outbound_item *item = aob->item;
nghttp2_buf *framebuf = &aob->framebuf;
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame;
frame = nghttp2_outbound_item_get_ctrl_frame(session->aob.item);
frame = nghttp2_outbound_item_get_ctrl_frame(item);
if(frame->hd.type == NGHTTP2_HEADERS ||
frame->hd.type == NGHTTP2_PUSH_PROMISE) {
if(session->aob.framebufmark < session->aob.framebuflen) {
if(framebuf->mark < framebuf->last) {
nghttp2_frame_hd cont_hd;
cont_hd.length = nghttp2_min(session->aob.framebuflen -
session->aob.framebufmark,
cont_hd.length = nghttp2_min(framebuf->last - framebuf->mark,
NGHTTP2_MAX_FRAME_LENGTH);
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 */
session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH;
if(cont_hd.length + session->aob.framebufmark ==
session->aob.framebuflen) {
framebuf->pos -= NGHTTP2_FRAME_HEAD_LENGTH;
if(cont_hd.length + framebuf->mark == framebuf->last) {
size_t padlen;
if(cont_hd.length < frame->headers.padlen) {
padlen = cont_hd.length;
} else {
@ -1584,34 +1627,41 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
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));
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
nghttp2_frame_set_pad(framebuf, &cont_hd.flags, padlen);
rv = nghttp2_frame_add_pad(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&cont_hd.flags,
cont_hd.length - padlen,
padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
/* we reuses previous up to 2 bytes for PAD_HIGH and
PAD_LOW. Because of this, session->aob.framebuflen is 1
or 2 bytes longer. Re-compute the value here. */
session->aob.framebuflen = session->aob.framebufmark =
session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH +
cont_hd.length;
framebuf->mark = framebuf->last;
} else {
cont_hd.flags = NGHTTP2_FLAG_NONE;
session->aob.framebufmark += cont_hd.length;
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(session->aob.framebuf +
session->aob.framebufoff,
&cont_hd);
nghttp2_frame_pack_frame_hd(framebuf->pos, &cont_hd);
return 0;
}
}
@ -1754,7 +1804,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
nghttp2_outbound_item* next_item;
nghttp2_stream *stream;
data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item);
data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id);
/* We update flow control window after a frame was completely
sent. This is possible because we choose payload length not to
@ -1786,7 +1836,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
if(data_frame->eof ||
nghttp2_session_predicate_data_send(session,
data_frame->hd.stream_id) != 0) {
nghttp2_active_outbound_item_reset(&session->aob);
nghttp2_active_outbound_item_reset(aob);
return 0;
}
/* Assuming stream is not NULL */
@ -1795,30 +1845,27 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
/* If priority of this stream is higher or equal to other stream
waiting at the top of the queue, we continue to send this
data. */
if(next_item == NULL || session->aob.item->pri < next_item->pri) {
if(next_item == NULL || aob->item->pri < next_item->pri) {
size_t next_readmax;
next_readmax = nghttp2_session_next_data_read(session, stream);
if(next_readmax == 0) {
nghttp2_stream_defer_data(stream, session->aob.item,
nghttp2_stream_defer_data(stream, aob->item,
NGHTTP2_DEFERRED_FLOW_CONTROL);
session->aob.item = NULL;
nghttp2_active_outbound_item_reset(&session->aob);
aob->item = NULL;
nghttp2_active_outbound_item_reset(aob);
return 0;
}
rv = nghttp2_session_pack_data(session,
&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
next_readmax,
rv = nghttp2_session_pack_data(session, framebuf, next_readmax,
data_frame);
if(nghttp2_is_fatal(rv)) {
return rv;
}
if(rv == NGHTTP2_ERR_DEFERRED) {
nghttp2_stream_defer_data(stream, session->aob.item,
NGHTTP2_DEFERRED_NONE);
session->aob.item = NULL;
nghttp2_active_outbound_item_reset(&session->aob);
nghttp2_stream_defer_data(stream, aob->item, NGHTTP2_DEFERRED_NONE);
aob->item = NULL;
nghttp2_active_outbound_item_reset(aob);
return 0;
}
if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@ -1828,24 +1875,26 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
rv = nghttp2_session_add_rst_stream(session,
data_frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
nghttp2_active_outbound_item_reset(&session->aob);
nghttp2_active_outbound_item_reset(aob);
if(nghttp2_is_fatal(rv)) {
return rv;
}
return 0;
}
assert(rv >= 0);
session->aob.framebuflen = session->aob.framebufmark = rv;
framebuf->mark = framebuf->last;
return 0;
}
/* Update seq to interleave other streams with the same
priority. */
session->aob.item->seq = session->next_seq++;
rv = nghttp2_pq_push(&session->ob_pq, session->aob.item);
aob->item->seq = session->next_seq++;
rv = nghttp2_pq_push(&session->ob_pq, aob->item);
if(nghttp2_is_fatal(rv)) {
return rv;
}
session->aob.item = NULL;
aob->item = NULL;
nghttp2_active_outbound_item_reset(&session->aob);
return 0;
}
@ -1857,10 +1906,15 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
const uint8_t **data_ptr)
{
int rv;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
aob = &session->aob;
framebuf = &aob->framebuf;
*data_ptr = NULL;
for(;;) {
switch(session->aob.state) {
switch(aob->state) {
case NGHTTP2_OB_POP_ITEM: {
nghttp2_outbound_item *item;
ssize_t framebuflen;
@ -1895,7 +1949,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
}
nghttp2_outbound_item_free(item);
free(item);
nghttp2_active_outbound_item_reset(&session->aob);
nghttp2_active_outbound_item_reset(aob);
if(framebuflen == NGHTTP2_ERR_HEADER_COMP) {
/* If header compression error occurred, should terminiate
@ -1908,32 +1962,43 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
}
break;
}
session->aob.item = item;
session->aob.framebuflen = framebuflen;
aob->item = item;
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame = nghttp2_outbound_item_get_ctrl_frame(item);
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_FRAME_LENGTH */
session->aob.framebufmark =
session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH +
nghttp2_get_uint16(session->aob.framebuf + session->aob.framebufoff);
frame = nghttp2_outbound_item_get_ctrl_frame(item);
framebuf->mark = framebuf->pos + NGHTTP2_FRAME_HEAD_LENGTH +
nghttp2_get_uint16(framebuf->pos);
rv = session_call_before_frame_send(session, frame);
if(nghttp2_is_fatal(rv)) {
return rv;
}
} else {
session->aob.framebufmark = session->aob.framebuflen;
framebuf->mark = framebuf->last;
}
session->aob.state = NGHTTP2_OB_SEND_DATA;
DEBUGF(fprintf(stderr, "start transmitting type %d frame %zd bytes\n",
framebuf->pos[2], framebuf->mark - framebuf->pos));
aob->state = NGHTTP2_OB_SEND_DATA;
break;
}
case NGHTTP2_OB_SEND_DATA: {
size_t datalen;
if(session->aob.framebufoff == session->aob.framebufmark) {
if(framebuf->pos == framebuf->mark) {
DEBUGF(fprintf(stderr, "end transmission of frame, left %zd\n",
framebuf->last - framebuf->mark));
/* Frame has completely sent */
rv = nghttp2_session_after_frame_sent(session);
if(rv < 0) {
@ -1945,11 +2010,11 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
break;
}
*data_ptr = session->aob.framebuf + session->aob.framebufoff;
datalen = session->aob.framebufmark - session->aob.framebufoff;
*data_ptr = framebuf->pos;
datalen = framebuf->mark - framebuf->pos;
/* We increment the offset here. If send_callback does not send
everything, we will adjust it. */
session->aob.framebufoff += datalen;
framebuf->pos += datalen;
return datalen;
}
@ -1962,6 +2027,9 @@ int nghttp2_session_send(nghttp2_session *session)
const uint8_t *data;
ssize_t datalen;
ssize_t sentlen;
nghttp2_buf *framebuf;
framebuf = &session->aob.framebuf;
for(;;) {
datalen = nghttp2_session_mem_send(session, &data);
@ -1973,13 +2041,14 @@ int nghttp2_session_send(nghttp2_session *session)
if(sentlen < 0) {
if(sentlen == NGHTTP2_ERR_WOULDBLOCK) {
/* Transmission canceled. Rewind the offset */
session->aob.framebufoff -= datalen;
framebuf->pos -= datalen;
return 0;
}
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
/* Rewind the offset to the amount of unsent bytes */
session->aob.framebufoff -= datalen - sentlen;
framebuf->pos -= datalen - sentlen;
}
return 0;
}
@ -2083,82 +2152,6 @@ static int session_detect_idle_stream(nghttp2_session *session,
return 0;
}
/*
* Inflates header block in the memory pointed by |in| with |inlen|
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
* call this function again, until it returns 0 or one of negative
* error code. If |call_header_cb| is zero, the on_header_callback
* are not invoked and the function never return NGHTTP2_ERR_PAUSE. If
* the given |in| is the last chunk of header block, the |final| must
* be nonzero. If header block is successfully processed (which is
* indicated by the return value 0, NGHTTP2_ERR_PAUSE or
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed
* input bytes is assigned to the |*readlen_ptr|.
*
* This function return 0 if it succeeds, or one of the negative error
* codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
* The callback returns this error code, indicating that this
* stream should be RST_STREAMed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_PAUSE
* The callback function returned NGHTTP2_ERR_PAUSE
* NGHTTP2_ERR_HEADER_COMP
* Header decompression failed
*/
static ssize_t inflate_header_block(nghttp2_session *session,
nghttp2_frame *frame,
size_t *readlen_ptr,
uint8_t *in, size_t inlen,
int final, int call_header_cb)
{
ssize_t rv;
int inflate_flags;
nghttp2_nv nv;
*readlen_ptr = 0;
DEBUGF(fprintf(stderr, "processing header block %zu bytes\n", inlen));
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(&session->hd_inflater, &nv, &inflate_flags,
in, inlen, final);
if(nghttp2_is_fatal(rv)) {
return rv;
}
if(rv < 0) {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_COMPRESSION_ERROR);
if(rv != 0) {
return rv;
}
return NGHTTP2_ERR_HEADER_COMP;
}
in += rv;
inlen -= rv;
*readlen_ptr += rv;
if(call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) {
rv = session_call_on_header(session, frame, &nv);
/* This handles NGHTTP2_ERR_PAUSE and
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */
if(rv != 0) {
return rv;
}
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
break;
}
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}
return 0;
}
/*
* Handles frame size error.
*
@ -2238,6 +2231,87 @@ static int nghttp2_session_inflate_handle_invalid_connection
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
}
/*
* Inflates header block in the memory pointed by |in| with |inlen|
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
* call this function again, until it returns 0 or one of negative
* error code. If |call_header_cb| is zero, the on_header_callback
* are not invoked and the function never return NGHTTP2_ERR_PAUSE. If
* the given |in| is the last chunk of header block, the |final| must
* be nonzero. If header block is successfully processed (which is
* indicated by the return value 0, NGHTTP2_ERR_PAUSE or
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed
* input bytes is assigned to the |*readlen_ptr|.
*
* This function return 0 if it succeeds, or one of the negative error
* codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
* The callback returns this error code, indicating that this
* stream should be RST_STREAMed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_PAUSE
* The callback function returned NGHTTP2_ERR_PAUSE
* NGHTTP2_ERR_HEADER_COMP
* Header decompression failed
*/
static ssize_t inflate_header_block(nghttp2_session *session,
nghttp2_frame *frame,
size_t *readlen_ptr,
uint8_t *in, size_t inlen,
int final, int call_header_cb)
{
ssize_t rv;
int inflate_flags;
nghttp2_nv nv;
*readlen_ptr = 0;
DEBUGF(fprintf(stderr, "processing header block %zu bytes\n", inlen));
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(&session->hd_inflater, &nv, &inflate_flags,
in, inlen, final);
if(nghttp2_is_fatal(rv)) {
return rv;
}
if(rv < 0) {
if(session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) {
rv = nghttp2_session_handle_invalid_connection
(session, frame, NGHTTP2_COMPRESSION_ERROR);
} else {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_COMPRESSION_ERROR);
}
if(rv != 0) {
return rv;
}
return NGHTTP2_ERR_HEADER_COMP;
}
in += rv;
inlen -= rv;
*readlen_ptr += rv;
if(call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) {
rv = session_call_on_header(session, frame, &nv);
/* This handles NGHTTP2_ERR_PAUSE and
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */
if(rv != 0) {
return rv;
}
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
break;
}
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}
return 0;
}
/*
* Decompress header blocks of incoming request HEADERS and also call
* additional callbacks. This function can be called again if this
@ -4488,48 +4562,53 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
}
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_buf *buf,
size_t datamax,
nghttp2_private_data *frame)
{
size_t payloadoff;
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_hd hd;
/* 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|. */
*bufoff_ptr = 2;
payloadoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH;
framelen = payloadoff + datamax;
buf->pos += 2;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
framelen = NGHTTP2_FRAME_HDLEN + datamax;
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) {
return rv;
}
eof_flags = 0;
payloadlen = frame->data_prd.read_callback
(session, frame->hd.stream_id, (*buf_ptr) + payloadoff, datamax,
(session, frame->hd.stream_id, buf->pos + NGHTTP2_FRAME_HDLEN, datamax,
&eof_flags, &frame->data_prd.source, session->user_data);
if(payloadlen == NGHTTP2_ERR_DEFERRED ||
payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
DEBUGF(fprintf(stderr, "DATA postponed due to %s\n",
nghttp2_strerror(payloadlen)));
return payloadlen;
}
if(payloadlen < 0 || datamax < (size_t)payloadlen) {
/* This is the error code when callback is failed. */
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
buf->last = buf->pos + NGHTTP2_FRAME_HDLEN + payloadlen;
/* Clear flags, because this may contain previous flags of previous
DATA */
frame->hd.flags &= (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT);
@ -4545,7 +4624,9 @@ 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;
@ -4556,25 +4637,31 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
if(nghttp2_is_fatal(padded_payloadlen)) {
return padded_payloadlen;
}
rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags,
payloadlen, padded_payloadlen - payloadlen);
padlen = padded_payloadlen - payloadlen;
rv = session_reserve_pad_trail(session, padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
frame->padlen = padded_payloadlen - payloadlen;
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_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
nghttp2_put_uint16be(&(*buf_ptr)[*bufoff_ptr], frame->hd.length);
memset(buf->pos, 0, NGHTTP2_FRAME_HEAD_LENGTH);
(*buf_ptr)[*bufoff_ptr + 3] = flags;
nghttp2_put_uint32be(&(*buf_ptr)[*bufoff_ptr + 4], frame->hd.stream_id);
hd = frame->hd;
hd.flags = flags;
return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr;
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
return nghttp2_buf_len(buf);
}
void* nghttp2_session_get_stream_user_data(nghttp2_session *session,

View File

@ -38,6 +38,7 @@
#include "nghttp2_buffer.h"
#include "nghttp2_outbound_item.h"
#include "nghttp2_int.h"
#include "nghttp2_buf.h"
/*
* Option flags.
@ -54,27 +55,15 @@ typedef enum {
typedef struct {
nghttp2_outbound_item *item;
/* Buffer for outbound frames. Used to pack one frame. The memory
pointed by framebuf is initially allocated by
nghttp2_session_{client,server}_new() and deallocated by
nghttp2_session_del() */
uint8_t *framebuf;
/* The capacity of framebuf in bytes */
size_t framebufmax;
/* The length of the frame stored in framebuf */
size_t framebuflen;
/* The number of bytes has been sent */
size_t framebufoff;
/* Marks the last position to send. This is used to implement
CONTINUATION */
size_t framebufmark;
nghttp2_buf framebuf;
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 4096
#define NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH 16384
#define NGHTTP2_INITIAL_NV_BUFFER_LENGTH 4096
@ -538,8 +527,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,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_buf *buf,
size_t datamax,
nghttp2_private_data *frame);

View File

@ -291,8 +291,7 @@ cdef extern from 'nghttp2_hd.h':
size_t hd_table_bufsize_max)
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t nv_offset,
nghttp2_buf *buf,
nghttp2_nv *nva, size_t nvlen)
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
@ -303,3 +302,14 @@ cdef extern from 'nghttp2_hd.h':
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t index)
cdef extern from 'nghttp2_buf.h':
ctypedef struct nghttp2_buf:
uint8_t *pos
uint8_t *last
void nghttp2_buf_init(nghttp2_buf *buf)
void nghttp2_buf_free(nghttp2_buf *buf)

View File

@ -106,25 +106,36 @@ cdef class HDDeflater:
malloc(sizeof(cnghttp2.nghttp2_nv)*\
len(headers))
cdef cnghttp2.nghttp2_nv *nvap = nva
for k, v in headers:
nvap[0].name = k
nvap[0].namelen = len(k)
nvap[0].value = v
nvap[0].valuelen = len(v)
nvap += 1
cdef uint8_t *out = NULL
cdef cnghttp2.nghttp2_buf buf
cdef size_t outcap = 0
cdef ssize_t rv
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &out, &outcap,
0, nva, len(headers))
cnghttp2.nghttp2_buf_init(&buf)
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &buf,
nva, len(headers))
free(nva)
if rv < 0:
cnghttp2.nghttp2_buf_free(&buf);
raise Exception(_strerror(rv))
cdef bytes res
try:
res = out[:rv]
res = buf.pos[:rv]
finally:
cnghttp2.nghttp2_free(out)
cnghttp2.nghttp2_buf_free(&buf)
return res
def set_no_refset(self, no_refset):

View File

@ -72,12 +72,15 @@ static void to_hex(char *dest, const uint8_t *src, size_t len)
}
static void output_to_json(nghttp2_hd_deflater *deflater,
const uint8_t *buf, size_t len, size_t inputlen,
nghttp2_buf *buf, size_t inputlen,
nghttp2_nv *nva, size_t nvlen,
int seq)
{
json_t *obj;
char *hex = NULL;
size_t len;
len = nghttp2_buf_len(buf);
if(len > 0) {
hex = malloc(len * 2);
@ -88,7 +91,7 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
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, len);
to_hex(hex, buf->pos, len);
if(len == 0) {
json_object_set_new(obj, "wire", json_string(""));
} else {
@ -114,17 +117,21 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_nv *nva, size_t nvlen, size_t inputlen, int seq)
{
ssize_t rv;
uint8_t *buf = NULL;
size_t buflen = 0;
rv = nghttp2_hd_deflate_hd(deflater, &buf, &buflen, 0, nva, nvlen);
nghttp2_buf buf;
nghttp2_buf_init(&buf);
rv = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
if(rv < 0) {
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE);
}
input_sum += inputlen;
output_sum += rv;
output_to_json(deflater, buf, rv, inputlen, nva, nvlen, seq);
free(buf);
output_to_json(deflater, &buf, inputlen, nva, nvlen, seq);
nghttp2_buf_free(&buf);
}
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)

View File

@ -202,6 +202,12 @@ int main(int argc, char* argv[])
test_nghttp2_session_pack_data_with_padding) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding",
test_nghttp2_session_pack_headers_with_padding) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding2",
test_nghttp2_session_pack_headers_with_padding2) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding3",
test_nghttp2_session_pack_headers_with_padding3) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding4",
test_nghttp2_session_pack_headers_with_padding4) ||
!CU_add_test(pSuite, "pack_settings_payload",
test_nghttp2_pack_settings_payload) ||
!CU_add_test(pSuite, "frame_pack_headers",

View File

@ -72,14 +72,14 @@ void test_nghttp2_frame_pack_headers()
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_headers frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_nv *nva;
ssize_t nvlen;
nva_out out;
ssize_t nv_offset;
ssize_t hdblocklen;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater);
@ -91,22 +91,22 @@ 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, &buflen, &bufoff, &frame,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
framelen - bufoff));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(nghttp2_buf_len(&buf) - 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);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH;
CU_ASSERT(framelen - nv_offset ==
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf + nv_offset, framelen - nv_offset));
buf.pos + NGHTTP2_FRAME_HDLEN, hdblocklen));
CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
@ -114,32 +114,33 @@ void test_nghttp2_frame_pack_headers()
nghttp2_frame_headers_free(&oframe);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
memset(&oframe, 0, sizeof(oframe));
/* Next, include PRIORITY flag */
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
framelen - bufoff));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(nghttp2_buf_len(&buf) - 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);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4;
CU_ASSERT(framelen - nv_offset ==
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf + nv_offset, framelen - nv_offset));
buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
nghttp2_nv_array_sort(out.nva, out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
nva_out_reset(&out);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_headers_free(&oframe);
nghttp2_frame_headers_free(&frame);
nghttp2_hd_inflate_free(&inflater);
@ -150,9 +151,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
{
nghttp2_hd_deflater deflater;
nghttp2_headers frame;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_nv *nva;
ssize_t nvlen;
@ -161,6 +160,8 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
size_t big_hdslen = ARRLEN(big_hds);
size_t i;
nghttp2_buf_init(&buf);
for(i = 0; i < big_hdslen; ++i) {
big_hds[i].name = (uint8_t*)"header";
big_hds[i].value = malloc(big_vallen+1);
@ -176,12 +177,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, &buflen, &bufoff, &frame,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen);
nghttp2_frame_headers_free(&frame);
free(buf);
nghttp2_buf_free(&buf);
for(i = 0; i < big_hdslen; ++i) {
free(big_hds[i].value);
}
@ -191,16 +191,21 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
void test_nghttp2_frame_pack_priority(void)
{
nghttp2_priority frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_priority_init(&frame, 1000000007, 1 << 30);
framelen = nghttp2_frame_pack_priority(&buf, &buflen, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
framelen = nghttp2_frame_pack_priority(&buf, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd);
CU_ASSERT(1 << 30 == oframe.pri);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_priority_free(&oframe);
nghttp2_frame_priority_free(&frame);
}
@ -208,16 +213,21 @@ void test_nghttp2_frame_pack_priority(void)
void test_nghttp2_frame_pack_rst_stream(void)
{
nghttp2_rst_stream frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_rst_stream_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR);
framelen = nghttp2_frame_pack_rst_stream(&buf, &buflen, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
framelen = nghttp2_frame_pack_rst_stream(&buf, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd);
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_rst_stream_free(&oframe);
nghttp2_frame_rst_stream_free(&frame);
}
@ -225,24 +235,33 @@ void test_nghttp2_frame_pack_rst_stream(void)
void test_nghttp2_frame_pack_settings()
{
nghttp2_settings frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
int i;
nghttp2_settings_entry iv[3];
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = 256;
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
iv[1].value = 16384;
iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
iv[2].value = 4096;
nghttp2_settings_entry iv[] =
{
{
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 256
},
{
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 16384
},
{
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE, 4096
}
};
nghttp2_buf_init(&buf);
nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE,
nghttp2_frame_iv_copy(iv, 3), 3);
framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame);
framelen = nghttp2_frame_pack_settings(&buf, &frame);
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH +
3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
CU_ASSERT(3 == oframe.niv);
@ -251,7 +270,7 @@ void test_nghttp2_frame_pack_settings()
CU_ASSERT(iv[i].value == oframe.iv[i].value);
}
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_settings_free(&frame);
nghttp2_frame_settings_free(&oframe);
}
@ -261,14 +280,14 @@ void test_nghttp2_frame_pack_push_promise()
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
nghttp2_push_promise frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_nv *nva;
ssize_t nvlen;
nva_out out;
ssize_t nv_offset;
ssize_t hdblocklen;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater);
@ -278,26 +297,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, &buflen, &bufoff, &frame,
&deflater);
framelen = nghttp2_frame_pack_push_promise(&buf, &frame, &deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe,
buf + bufoff, framelen - bufoff));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_PUSH_PROMISE,
NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd);
CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4;
CU_ASSERT(framelen - nv_offset ==
inflate_hd(&inflater, &out, buf + nv_offset, framelen - nv_offset));
hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out,
buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
CU_ASSERT(nvvalueeq("GET", &out.nva[0]));
nva_out_reset(&out);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_push_promise_free(&oframe);
nghttp2_frame_push_promise_free(&frame);
nghttp2_hd_inflate_free(&inflater);
@ -307,17 +327,22 @@ void test_nghttp2_frame_pack_push_promise()
void test_nghttp2_frame_pack_ping(void)
{
nghttp2_ping frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
const uint8_t opaque_data[] = "01234567";
nghttp2_buf_init(&buf);
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data);
framelen = nghttp2_frame_pack_ping(&buf, &buflen, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
framelen = nghttp2_frame_pack_ping(&buf, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
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);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_ping_free(&oframe);
nghttp2_frame_ping_free(&frame);
}
@ -325,17 +350,20 @@ void test_nghttp2_frame_pack_ping(void)
void test_nghttp2_frame_pack_goaway()
{
nghttp2_goaway frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
size_t opaque_data_len = 16;
uint8_t *opaque_data = malloc(opaque_data_len);
nghttp2_buf_init(&buf);
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, &buflen, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
framelen = nghttp2_frame_pack_goaway(&buf, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
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);
@ -344,7 +372,8 @@ void test_nghttp2_frame_pack_goaway()
CU_ASSERT(NULL == oframe.opaque_data);
/* CU_ASSERT(opaque_data_len == oframe.opaque_data_len); */
/* CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, opaque_data_len) == 0); */
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_goaway_free(&oframe);
nghttp2_frame_goaway_free(&frame);
}
@ -352,19 +381,22 @@ void test_nghttp2_frame_pack_goaway()
void test_nghttp2_frame_pack_window_update(void)
{
nghttp2_window_update frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_window_update_init(&frame, NGHTTP2_FLAG_NONE,
1000000007, 4096);
framelen = nghttp2_frame_pack_window_update(&buf, &buflen,
&frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
framelen = nghttp2_frame_pack_window_update(&buf, &frame);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_WINDOW_UPDATE, NGHTTP2_FLAG_NONE,
1000000007, &oframe.hd);
CU_ASSERT(4096 == oframe.window_size_increment);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_window_update_free(&oframe);
nghttp2_frame_window_update_free(&frame);
}

View File

@ -52,77 +52,83 @@ void test_nghttp2_hd_deflate(void)
MAKE_NV("cookie", "k1=v1")};
nghttp2_nv nva5[] = {MAKE_NV(":path", "/style.css"),
MAKE_NV("x-nghttp2", "")};
size_t nv_offset = 12;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t blocklen;
nva_out out;
nghttp2_buf_init(&buf);
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, &buflen, nv_offset, nva1,
sizeof(nva1)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva1, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Second headers */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva2,
sizeof(nva2)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva2, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Third headers, including same header field name, but value is not
the same. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva3,
sizeof(nva3)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva3, ARRLEN(nva3));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva3, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Fourth headers, including duplicate header fields. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva4,
sizeof(nva4)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva4, ARRLEN(nva4));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva4, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Fifth headers includes empty value */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva5,
sizeof(nva5)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva5, ARRLEN(nva5));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva5, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Cleanup */
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -136,41 +142,46 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
nghttp2_nv nva2[] = {MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha")};
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t blocklen;
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
/* 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, &buflen, 0, nva1,
sizeof(nva1)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva1, out.nva, 2);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* 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, &buflen, 0, nva2,
sizeof(nva2)/sizeof(nghttp2_nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
CU_ASSERT(blocklen == 6);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva2, out.nva, 3);
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Cleanup */
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -181,8 +192,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = {MAKE_NV("h1", ""),
MAKE_NV("h2", "")};
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
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
@ -191,6 +201,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nva_out out;
size_t i;
nghttp2_buf_init(&buf);
nva_out_init(&out);
memset(value, '0', sizeof(value));
for(i = 0; i < 2; ++i) {
@ -203,35 +215,42 @@ 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, &buflen, 0, nva, 1);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 1);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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);
/* Encode with second header */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
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, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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);
CU_ASSERT(1 == deflater.ctx.hd_table.len);
CU_ASSERT(1 == inflater.ctx.hd_table.len);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -240,8 +259,7 @@ void test_nghttp2_hd_deflate_clear_refset(void)
{
nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv[] = {
MAKE_NV(":path", "/"),
@ -250,6 +268,8 @@ void test_nghttp2_hd_deflate_clear_refset(void)
size_t i;
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_deflate_init2(&deflater,
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
@ -257,18 +277,18 @@ 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, &buflen, 0,
nv, ARRLEN(nv));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nv, ARRLEN(nv));
CU_ASSERT(blocklen > 1);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(ARRLEN(nv) == out.nvlen);
assert_nv_equal(nv, out.nva, ARRLEN(nv));
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
}
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -276,9 +296,8 @@ void test_nghttp2_hd_deflate_clear_refset(void)
void test_nghttp2_hd_inflate_indname_noinc(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv[] = {
/* Huffman */
MAKE_NV("user-agent", "nghttp2"),
@ -288,42 +307,53 @@ void test_nghttp2_hd_inflate_indname_noinc(void)
size_t i;
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
nv[i].value, nv[i].valuelen,
0));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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);
}
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_inc(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
nv.value, nv.valuelen, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
@ -333,33 +363,38 @@ void test_nghttp2_hd_inflate_indname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_inc_eviction(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
uint8_t value[1024];
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 13,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 14,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 15,
value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 16,
value, sizeof(value), 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(4 == out.nvlen);
CU_ASSERT(14 == out.nva[0].namelen);
@ -367,20 +402,20 @@ 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);
CU_ASSERT(3 == inflater.ctx.hd_table.len);
CU_ASSERT(GET_TABLE_ENT(&inflater.ctx, 0)->flags & NGHTTP2_HD_FLAG_REFSET);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_noinc(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv[] = {
/* Expecting huffman for both */
MAKE_NV("my-long-content-length", "nghttp2"),
@ -394,40 +429,49 @@ void test_nghttp2_hd_inflate_newname_noinc(void)
size_t i;
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv[i], 0));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv[i], 0));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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);
}
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_inc(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
@ -437,20 +481,21 @@ void test_nghttp2_hd_inflate_newname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_clearall_inc(void)
{
nghttp2_hd_inflater inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_buf buf;
ssize_t blocklen;
nghttp2_nv nv;
uint8_t value[4060];
nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out);
/* Total 4097 bytes space required to hold this entry */
nv.name = (uint8_t*)"alpha";
@ -461,18 +506,22 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1);
@ -484,18 +533,21 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
header table */
nv.valuelen = sizeof(value) - 1;
offset = 0;
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
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);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
}
@ -531,11 +583,11 @@ void test_nghttp2_hd_change_table_size(void)
nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = { MAKE_NV(":method", "GET"),
MAKE_NV(":path", "/") };
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t rv;
nva_out out;
size_t offset;
nghttp2_buf_init(&buf);
nva_out_init(&out);
@ -554,17 +606,19 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
/* inflater changes header table size to 1024 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024));
@ -577,17 +631,19 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
/* inflater changes header table size to 0 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0));
@ -602,25 +658,27 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
/* Check table buffer is expanded */
buf = NULL;
buflen = 0;
nghttp2_buf_init(&buf);
nghttp2_hd_deflate_init2(&deflater, 8192);
nghttp2_hd_inflate_init(&inflater);
@ -635,17 +693,19 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383));
@ -657,26 +717,29 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
/* Lastly, check the error condition */
offset = 0;
rv = nghttp2_hd_emit_table_size(&buf, &buflen, &offset, 25600);
rv = nghttp2_hd_emit_table_size(&buf, 25600);
CU_ASSERT(rv == 0);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP ==
inflate_hd(&inflater, &out, buf, offset));
inflate_hd(&inflater, &out, buf.pos, nghttp2_buf_len(&buf)));
nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
@ -690,19 +753,21 @@ 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, &buflen, 0, nva, 2);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
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, rv));
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
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);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
@ -711,22 +776,25 @@ static void check_deflate_inflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater,
nghttp2_nv *nva, size_t nvlen)
{
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_buf buf;
ssize_t blocklen;
nva_out out;
nva_out_init(&out);
blocklen = nghttp2_hd_deflate_hd(deflater, &buf, &buflen, 0, nva, nvlen);
assert(blocklen >= 0);
nghttp2_buf_init(&buf);
CU_ASSERT(blocklen == inflate_hd(inflater, &out, buf, blocklen));
nva_out_init(&out);
blocklen = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
CU_ASSERT(blocklen >= 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(inflater, &out, buf.pos, blocklen));
CU_ASSERT(nvlen == out.nvlen);
assert_nv_equal(nva, out.nva, nvlen);
nva_out_reset(&out);
free(buf);
nghttp2_buf_free(&buf);
}
void test_nghttp2_hd_deflate_inflate(void)

View File

@ -346,37 +346,39 @@ void test_nghttp2_session_recv(void)
const nghttp2_nv nv[] = {
MAKE_NV("url", "/")
};
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_frame frame;
size_t i;
ssize_t i;
nghttp2_outbound_item *item;
nghttp2_nv *nva;
ssize_t nvlen;
nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.recv_callback = scripted_recv_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
user_data.df = &df;
nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater);
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(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
/* Send 1 byte per each read */
for(i = 0; i < framelen - bufoff; ++i) {
for(i = 0; i < nghttp2_buf_len(&buf); ++i) {
df.feedseq[i] = 1;
}
nghttp2_frame_headers_free(&frame.headers);
user_data.frame_recv_cb_called = 0;
@ -385,16 +387,16 @@ void test_nghttp2_session_recv(void)
}
CU_ASSERT(1 == user_data.frame_recv_cb_called);
nghttp2_buf_reset(&buf);
/* 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(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
nghttp2_frame_headers_free(&frame.headers);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.frame_recv_cb_called);
@ -405,15 +407,21 @@ void test_nghttp2_session_recv(void)
/* Some tests for frame too large */
nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_buf_reset(&buf);
/* Receive PING with too large payload */
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
nghttp2_reserve_buffer(&framedata, &framedatalen, 77);
framelen = nghttp2_frame_pack_ping(&framedata, &framedatalen, &frame.ping);
framelen = nghttp2_frame_pack_ping(&buf, &frame.ping);
/* 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_frame_ping_free(&frame.ping);
nghttp2_put_uint16be(&framedata[0],
framedatalen - NGHTTP2_FRAME_HEAD_LENGTH);
scripted_data_feed_init(&df, framedata, framedatalen);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == user_data.frame_recv_cb_called);
@ -422,7 +430,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));
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_session_del(session);
}
@ -432,13 +440,13 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
nghttp2_session_callbacks callbacks;
scripted_data_feed df;
my_user_data user_data;
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_frame frame;
nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
@ -450,17 +458,17 @@ 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(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -474,15 +482,15 @@ void test_nghttp2_session_recv_invalid_frame(void)
const nghttp2_nv nv[] = {
MAKE_NV("url", "/")
};
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
nghttp2_buf buf;
ssize_t framelen;
nghttp2_frame frame;
nghttp2_nv *nva;
ssize_t nvlen;
nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
callbacks.send_callback = null_send_callback;
@ -495,11 +503,11 @@ 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(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
@ -507,13 +515,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, framedata + bufoff, framelen - bufoff);
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(0 == user_data.frame_send_cb_called);
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_hd_deflate_free(&deflater);
@ -672,11 +680,7 @@ void test_nghttp2_session_recv_continuation(void)
nghttp2_nv *nva;
size_t nvlen;
nghttp2_frame frame;
uint8_t *framedata = NULL;
size_t framedatacap = 0;
size_t framedatalen;
size_t bufoff;
size_t framedataoff;
nghttp2_buf buf;
ssize_t rv;
my_user_data ud;
nghttp2_hd_deflater deflater;
@ -684,6 +688,8 @@ void test_nghttp2_session_recv_continuation(void)
size_t datalen;
nghttp2_frame_hd cont_hd;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback;
@ -696,15 +702,16 @@ 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);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap,
&bufoff,
&frame.headers,
&deflater);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata + bufoff, 9);
/* HEADERS's payload is 1 byte */
memcpy(data, buf.pos, 9);
datalen = 9;
framedataoff = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 1;
buf.pos += 9;
nghttp2_put_uint16be(data, 1);
@ -715,25 +722,25 @@ void test_nghttp2_session_recv_continuation(void)
cont_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
datalen += NGHTTP2_FRAME_HEAD_LENGTH;
datalen += NGHTTP2_FRAME_HDLEN;
memcpy(data + datalen, framedata + framedataoff, cont_hd.length);
memcpy(data + datalen, buf.pos, cont_hd.length);
datalen += cont_hd.length;
framedataoff += cont_hd.length;
buf.pos += cont_hd.length;
/* Second CONTINUATION, rest of the bytes */
cont_hd.length = framedatalen - framedataoff;
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_HEAD_LENGTH;
memcpy(data + datalen, framedata + framedataoff, cont_hd.length);
memcpy(data + datalen, buf.pos, cont_hd.length);
datalen += cont_hd.length;
framedataoff += cont_hd.length;
buf.pos += cont_hd.length;
assert(framedataoff == framedatalen);
CU_ASSERT(0 == nghttp2_buf_len(&buf));
ud.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, datalen);
@ -752,19 +759,25 @@ 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);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff,
&frame.headers,
&deflater);
nghttp2_buf_reset(&buf);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata + bufoff, framedatalen - bufoff);
datalen = framedatalen - bufoff;
memcpy(data, buf.pos, nghttp2_buf_len(&buf));
datalen = nghttp2_buf_len(&buf);
/* Followed by PRIORITY */
nghttp2_frame_priority_init(&frame.priority, 1, 0);
framedatalen = nghttp2_frame_pack_priority(&framedata, &framedatacap,
&frame.priority);
memcpy(data + datalen, framedata, framedatalen);
datalen += framedatalen;
nghttp2_buf_reset(&buf);
rv = nghttp2_frame_pack_priority(&buf, &frame.priority);
CU_ASSERT(rv == 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);
@ -774,7 +787,7 @@ void test_nghttp2_session_recv_continuation(void)
CU_ASSERT(NGHTTP2_GOAWAY ==
OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session)));
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -790,14 +803,13 @@ void test_nghttp2_session_recv_premature_headers(void)
nghttp2_nv *nva;
size_t nvlen;
nghttp2_frame frame;
uint8_t *framedata = NULL;
size_t framedatacap = 0;
size_t framedatalen;
nghttp2_buf buf;
ssize_t rv;
my_user_data ud;
nghttp2_hd_deflater deflater;
nghttp2_outbound_item *item;
size_t bufoff = 0;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
@ -808,24 +820,24 @@ 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);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap,
&bufoff,
&frame.headers,
&deflater);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
/* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint16be(framedata + bufoff, frame.hd.length - 1);
rv = nghttp2_session_mem_recv(session, framedata + bufoff,
framedatalen - bufoff - 1);
CU_ASSERT((ssize_t)(framedatalen - bufoff - 1) == rv);
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);
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -843,14 +855,11 @@ void test_nghttp2_session_continue(void)
MAKE_NV("user-agent", "nghttp2/1.0.0"),
MAKE_NV("alpha", "bravo")
};
uint8_t *framedata = NULL;
size_t framedatalen = 0;
ssize_t framelen1, framelen2;
nghttp2_buf buf;
size_t framelen1, framelen2;
ssize_t rv;
uint8_t buffer[4096];
uint8_t *bufp = buffer;
size_t buflen;
size_t bufoff;
nghttp2_buf databuf;
nghttp2_frame frame;
nghttp2_nv *nva;
ssize_t nvlen;
@ -858,6 +867,9 @@ void test_nghttp2_session_continue(void)
nghttp2_frame_hd data_hd;
nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
nghttp2_buf_wrap_init(&databuf, buffer, sizeof(buffer));
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
@ -873,38 +885,40 @@ 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);
framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer, framedata + bufoff, framelen1 - bufoff);
framelen1 -= bufoff;
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);
framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
nghttp2_buf_reset(&buf);
rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff);
framelen2 -= bufoff;
buflen = framelen1 + framelen2;
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;
user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen);
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv;
buflen -= rv;
CU_ASSERT(rv >= 0);
databuf.pos += rv;
recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
CU_ASSERT((size_t)framelen1 - NGHTTP2_FRAME_HEAD_LENGTH ==
recv_frame->hd.length);
CU_ASSERT(framelen1 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
CU_ASSERT(1 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called);
@ -914,10 +928,11 @@ void test_nghttp2_session_continue(void)
/* get 2nd header field */
user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen);
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv;
buflen -= rv;
CU_ASSERT(rv >= 0);
databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called);
@ -927,15 +942,15 @@ void test_nghttp2_session_continue(void)
/* will call end_headers_callback and receive 2nd HEADERS and pause */
user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen);
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv;
buflen -= rv;
CU_ASSERT(rv >= 0);
databuf.pos += rv;
recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
CU_ASSERT((size_t)framelen2 - NGHTTP2_FRAME_HEAD_LENGTH ==
recv_frame->hd.length);
CU_ASSERT(framelen2 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
CU_ASSERT(1 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called);
@ -945,10 +960,11 @@ void test_nghttp2_session_continue(void)
/* get 2nd header field */
user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen);
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv;
buflen -= rv;
CU_ASSERT(rv >= 0);
databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called);
@ -959,10 +975,11 @@ void test_nghttp2_session_continue(void)
user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0;
user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen);
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv;
buflen -= rv;
CU_ASSERT(rv >= 0);
databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(0 == user_data.header_cb_called);
@ -973,13 +990,18 @@ void test_nghttp2_session_continue(void)
data_hd.type = NGHTTP2_DATA;
data_hd.flags = NGHTTP2_FLAG_NONE;
data_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(buffer, &data_hd);
bufp = buffer;
buflen = sizeof(buffer);
nghttp2_buf_reset(&databuf);
nghttp2_frame_pack_frame_hd(databuf.pos, &data_hd);
/* Intentionally specify larger buffer size to see pause is kicked
in. */
databuf.last = databuf.end;
user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buffer, sizeof(buffer));
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv);
CU_ASSERT(0 == user_data.frame_recv_cb_called);
@ -987,7 +1009,8 @@ void test_nghttp2_session_continue(void)
pause again in on_data_chunk_recv_callback since we pass same
DATA frame. */
user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buffer, sizeof(buffer));
rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv);
CU_ASSERT(1 == user_data.frame_recv_cb_called);
@ -997,7 +1020,7 @@ void test_nghttp2_session_continue(void)
CU_ASSERT(0 == rv);
CU_ASSERT(1 == user_data.frame_recv_cb_called);
free(framedata);
nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
}
@ -1022,13 +1045,16 @@ void test_nghttp2_session_add_frame(void)
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
memset(aux_data, 0, sizeof(nghttp2_headers_aux_data));
acc.length = 0;
user_data.acc = &acc;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data));
frame = malloc(sizeof(nghttp2_frame));
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame->headers,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
-1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
@ -2239,6 +2265,8 @@ void test_nghttp2_submit_data(void)
my_user_data ud;
nghttp2_private_data *data_frame;
nghttp2_frame_hd hd;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = block_count_send_callback;
@ -2246,6 +2274,8 @@ void test_nghttp2_submit_data(void)
data_prd.read_callback = fixed_length_data_source_read_callback;
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;
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
@ -2253,12 +2283,12 @@ void test_nghttp2_submit_data(void)
CU_ASSERT(0 == nghttp2_submit_data(session,
NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT, 1, &data_prd));
ud.block_count = 0;
CU_ASSERT(0 == nghttp2_session_send(session));
data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item);
nghttp2_frame_unpack_frame_hd(&hd,
session->aob.framebuf +
session->aob.framebufoff);
data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
/* frame->hd.flags has these flags */
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) ==
@ -2266,10 +2296,9 @@ 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(session->aob.item);
nghttp2_frame_unpack_frame_hd(&hd,
session->aob.framebuf +
session->aob.framebufoff);
data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
/* This is the last frame, so we must have following flags */
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) == hd.flags);
/* frame->hd.flags has these flags */
@ -4100,8 +4129,8 @@ void test_nghttp2_session_pack_data_with_padding(void)
/* Check reception of this DATA frame */
check_session_recv_data_with_padding
(session->aob.framebuf + session->aob.framebufoff,
session->aob.framebufmark - session->aob.framebufoff,
(session->aob.framebuf.pos,
session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen);
nghttp2_session_del(session);
@ -4126,8 +4155,8 @@ void test_nghttp2_session_pack_data_with_padding(void)
/* Check reception of this DATA frame */
check_session_recv_data_with_padding
(session->aob.framebuf + session->aob.framebufoff,
session->aob.framebufmark - session->aob.framebufoff,
(session->aob.framebuf.pos,
session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen);
nghttp2_session_del(session);
@ -4158,6 +4187,8 @@ void test_nghttp2_session_pack_headers_with_padding(void)
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is laid out across 2 frames: HEADERS and
CONTINUATION frames */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
@ -4193,6 +4224,147 @@ void test_nghttp2_session_pack_headers_with_padding(void)
nghttp2_session_del(session);
}
void test_nghttp2_session_pack_headers_with_padding2(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[16382];
size_t i;
for(i = 0; i < ARRLEN(nva); ++i) {
nva[i].name = (uint8_t*)":path";
nva[i].namelen = 5;
nva[i].value = (uint8_t*)"/";
nva[i].valuelen = 1;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is laid out across 2 frames: HEADERS and
CONTINUATION frames */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_session_pack_headers_with_padding3(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[8192];
size_t i;
for(i = 0; i < ARRLEN(nva); ++i) {
nva[i].name = (uint8_t*)":path";
nva[i].namelen = 5;
nva[i].value = (uint8_t*)"/";
nva[i].valuelen = 1;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is included in the last CONTINUATION
frame */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_session_pack_headers_with_padding4(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[1];
nva[0].name = (uint8_t*)":path";
nva[0].namelen = 5;
nva[0].value = (uint8_t*)"/";
nva[0].valuelen = 1;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is included in the first HEADERS frame */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length < NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_pack_settings_payload(void)
{
nghttp2_settings_entry iv[2];

View File

@ -92,6 +92,9 @@ void test_nghttp2_session_set_option(void);
void test_nghttp2_session_data_backoff_by_high_pri_frame(void);
void test_nghttp2_session_pack_data_with_padding(void);
void test_nghttp2_session_pack_headers_with_padding(void);
void test_nghttp2_session_pack_headers_with_padding2(void);
void test_nghttp2_session_pack_headers_with_padding3(void);
void test_nghttp2_session_pack_headers_with_padding4(void);
void test_nghttp2_pack_settings_payload(void);
#endif /* NGHTTP2_SESSION_TEST_H */

View File

@ -28,6 +28,11 @@
#include <CUnit/CUnit.h>
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf)
{
return unpack_frame(frame, buf->pos, nghttp2_buf_len(buf));
}
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len)
{
ssize_t rv = 0;

View File

@ -54,6 +54,8 @@
free(a); \
} while(0);
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf);
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len);
int strmemeq(const char *a, const uint8_t *b, size_t bn);