Commit 1db21953 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Implement padding for HEADERS and CONTINUATION

parent 10feab02
......@@ -151,9 +151,9 @@ typedef struct {
* @macro
*
* The default value of DATA padding alignment. See
* :member:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT`.
* :member:`NGHTTP2_OPT_PAD_ALIGNMENT`.
*/
#define NGHTTP2_DATA_PAD_ALIGNMENT 256
#define NGHTTP2_PAD_ALIGNMENT 256
/**
* @enum
......@@ -655,6 +655,11 @@ typedef struct {
* The frame header.
*/
nghttp2_frame_hd hd;
/**
* The length of the padding in this frame. This includes PAD_HIGH
* and PAD_LOW.
*/
size_t padlen;
/**
* The name/value pairs.
*/
......@@ -746,6 +751,11 @@ typedef struct {
* The frame header.
*/
nghttp2_frame_hd hd;
/**
* The length of the padding in this frame. This includes PAD_HIGH
* and PAD_LOW.
*/
size_t padlen;
/**
* The name/value pairs.
*/
......@@ -1324,13 +1334,14 @@ typedef enum {
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2,
/**
* This option specifies the alignment of padding in DATA frame. If
* this option is set to N, padding is added to DATA payload so that
* its payload length is divisible by N. Due to flow control,
* padding is not always added according to this alignment. The
* option value must be greater than or equal to 8.
* This option specifies the alignment of padding in frame
* payload. If this option is set to N, padding is added to frame
* payload so that its payload length is divisible by N. For DATA
* frame, due to flow control, padding is not always added according
* to this alignment. The option value must be greater than or equal
* to 8.
*/
NGHTTP2_OPT_DATA_PAD_ALIGNMENT = 1 << 3
NGHTTP2_OPT_PAD_ALIGNMENT = 1 << 3
} nghttp2_opt;
/**
......@@ -1352,9 +1363,9 @@ typedef struct {
*/
uint8_t no_auto_connection_window_update;
/**
* :enum:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT`
* :enum:`NGHTTP2_OPT_PAD_ALIGNMENT`
*/
uint16_t data_pad_alignment;
uint16_t pad_alignment;
} nghttp2_opt_set;
/**
......
......@@ -193,9 +193,9 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
}
}
size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame)
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
{
return frame->padlen
return padlen
- ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0)
- ((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0);
}
......@@ -214,19 +214,6 @@ void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
{}
/*
* Returns the offset of the name/header block in the HEADERS frame,
* including frame header length.
*/
static size_t headers_nv_offset(nghttp2_headers *frame)
{
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_FRAME_HEAD_LENGTH + 4;
} else {
return NGHTTP2_FRAME_HEAD_LENGTH;
}
}
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
{
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
......@@ -238,23 +225,41 @@ 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,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater)
nghttp2_hd_deflater *deflater,
size_t align)
{
ssize_t framelen;
size_t nv_offset = headers_nv_offset(frame);
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2;
size_t nv_offset =
payloadoff + nghttp2_frame_headers_payload_nv_offset(frame);
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;
}
framelen = rv + nv_offset;
if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) {
frame->hd.length = NGHTTP2_MAX_FRAME_LENGTH;
frame->hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv;
if(align > 0) {
ssize_t padlen;
padlen = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr,
&frame->hd.flags,
payloadlen,
payloadlen + align,
align);
if(padlen < 0) {
return padlen;
}
frame->padlen = padlen;
frame->hd.length = payloadlen + padlen;
} else {
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
*bufoff_ptr = 2;
frame->padlen = 0;
frame->hd.length = payloadlen;
}
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
nv_offset */
......@@ -262,13 +267,21 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr,
if(rv < 0) {
return rv;
}
memset(*buf_ptr, 0, nv_offset);
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
/* pack ctrl header after length is determined */
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd);
if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) {
/* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~(NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW);
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
} else {
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd);
}
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri);
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri);
}
return framelen;
return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr;
}
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
......@@ -276,7 +289,6 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
size_t payloadlen)
{
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
assert(payloadlen == 4);
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
} else {
frame->pri = NGHTTP2_PRI_DEFAULT;
......@@ -660,19 +672,23 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr,
payloadmax);
size_t padlen = nextlen - payloadlen;
size_t trail_padlen = 0;
size_t headoff = 2;
size_t trail_padoff = headoff + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen;
/* extra 2 bytes for PAD_HIGH and PAD_LOW. */
size_t trail_padoff = 2 + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen;
if(padlen > 257) {
headoff = 0;
*bufoff_ptr = 0;
trail_padlen = padlen - 2;
*flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
(*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8;
(*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff;
} else if(padlen > 0) {
headoff = 1;
*bufoff_ptr = 1;
trail_padlen = padlen - 1;
*flags_ptr |= NGHTTP2_FLAG_PAD_LOW;
(*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen;
} else {
*bufoff_ptr = 2;
return 0;
}
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr,
......@@ -682,7 +698,6 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr,
}
memset((*buf_ptr) + trail_padoff, 0, trail_padlen);
*bufoff_ptr = headoff;
return padlen;
}
......@@ -104,14 +104,21 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* expansion occurred, memory previously pointed by |*buf_ptr| may
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
*
* The first byte the frame is serialized is returned in the
* |*bufoff_ptr|.
*
* The |align| is used as padding alignment. If the |align| is zero,
* no padding is added.
*
* frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than
* NGHTTP2_MAX_FRAME_LENGTH, payload data is still serialized as is,
* 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 if it succeeds, or
* returns one of the following negative error codes:
* This function returns the size of packed frame (which includes
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
......@@ -122,8 +129,10 @@ 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,
nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
nghttp2_hd_deflater *deflater,
size_t align);
/*
* Unpacks HEADERS frame byte sequence into |frame|. This function
......@@ -427,10 +436,11 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
/*
* Returns the number of padding data after application data
* payload. Thus this does not include the PAD_HIGH and PAD_LOW.
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
* not include the PAD_HIGH and PAD_LOW.
*/
size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame);
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
uint8_t flags,
......
......@@ -173,6 +173,7 @@ static void nghttp2_inbound_frame_reset(nghttp2_session *session)
iframe->left = NGHTTP2_FRAME_HEAD_LENGTH;
iframe->niv = 0;
iframe->payloadleft = 0;
iframe->padlen = 0;
iframe->error_code = 0;
iframe->buflen = 0;
}
......@@ -223,11 +224,11 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
(*session_ptr)->opt_flags |=
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE;
}
if((opt_set_mask & NGHTTP2_OPT_DATA_PAD_ALIGNMENT) &&
opt_set->data_pad_alignment >= 8) {
(*session_ptr)->data_pad_alignment = opt_set->data_pad_alignment;
if((opt_set_mask & NGHTTP2_OPT_PAD_ALIGNMENT) &&
opt_set->pad_alignment >= 8) {
(*session_ptr)->pad_alignment = opt_set->pad_alignment;
} else {
(*session_ptr)->data_pad_alignment = NGHTTP2_DATA_PAD_ALIGNMENT;
(*session_ptr)->pad_alignment = NGHTTP2_PAD_ALIGNMENT;
}
(*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
......@@ -1119,8 +1120,10 @@ 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);
&session->hd_deflater,
session->pad_alignment);
if(framebuflen < 0) {
return framebuflen;
}
......@@ -1442,8 +1445,11 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
session->aob.framebufmark,
NGHTTP2_MAX_FRAME_LENGTH);
cont_hd.type = NGHTTP2_CONTINUATION;
if(cont_hd.length < NGHTTP2_MAX_FRAME_LENGTH) {
if(cont_hd.length + session->aob.framebufmark ==
session->aob.framebuflen) {
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
cont_hd.flags |=
(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW) & frame->hd.flags;
} else {
cont_hd.flags = NGHTTP2_FLAG_NONE;
}
......@@ -1456,9 +1462,6 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH;
return 0;
}
/* Update frame payload length to include data sent in
CONTINUATION frame. */
frame->hd.length = session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH;
}
rv = session_call_on_frame_send(session, frame);
if(nghttp2_is_fatal(rv)) {
......@@ -3318,24 +3321,73 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe)
* accordingly. If padding is set, this function returns 1. If no
* padding is set, this function returns 0. On error, returns -1.
*/
static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe)
static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe,
nghttp2_frame_hd *hd)
{
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
if((iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) == 0) {
if(hd->flags & NGHTTP2_FLAG_PAD_HIGH) {
if((hd->flags & NGHTTP2_FLAG_PAD_LOW) == 0) {
return -1;
}
iframe->state = NGHTTP2_IB_READ_NBYTE;
iframe->left = 2;
return 1;
}
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) {
if(hd->flags & NGHTTP2_FLAG_PAD_LOW) {
iframe->state = NGHTTP2_IB_READ_NBYTE;
iframe->left = 1;
return 1;
}
DEBUGF(fprintf(stderr, "no padding\n"));
return 0;
}
/*
* Computes number of padding based on flags. This function returns
* the calculated length if it succeeds, or -1.
*/
static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe)
{
size_t padlen;
padlen = iframe->buf[0];
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
padlen <<= 8;
padlen |= iframe->buf[1];
++padlen;
}
++padlen;
DEBUGF(fprintf(stderr, "padlen=%zu\n", padlen));
if(padlen > iframe->frame.hd.length) {
return -1;
}
iframe->padlen = padlen;
return padlen;
}
/*
* This function returns the effective payload length in the data of
* length |readlen| when the remaning payload is |payloadleft|. The
* |payloadleft| does not include |readlen|. If padding was started
* strictly before this data chunk, this function returns -1.
*/
static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
size_t payloadleft,
size_t readlen)
{
size_t trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame,
iframe->padlen);
if(trail_padlen > payloadleft) {
size_t padlen;
padlen = trail_padlen - payloadleft;
if(readlen < padlen) {
return -1;
} else {
return readlen - padlen;
}
}
return readlen;
}
ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
const uint8_t *in, size_t inlen)
{
......@@ -3363,7 +3415,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
switch(iframe->frame.hd.type) {
case NGHTTP2_DATA: {
DEBUGF(fprintf(stderr, "DATA\n"));
iframe->frame.data.padlen = 0;
/* Check stream is open. If it is not open or closing,
ignore payload. */
busy = 1;
......@@ -3377,7 +3428,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) {
return rv;
}
rv = inbound_frame_handle_pad(iframe);
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0) {
iframe->state = NGHTTP2_IB_IGN_DATA;
rv = nghttp2_session_terminate_session(session,
......@@ -3395,6 +3446,20 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
}
case NGHTTP2_HEADERS:
DEBUGF(fprintf(stderr, "HEADERS\n"));
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
return rv;
}
break;
}
if(rv == 1) {
break;
}
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) {
if(iframe->payloadleft < 4) {
busy = 1;
......@@ -3497,16 +3562,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
switch(iframe->frame.hd.type) {
case NGHTTP2_DATA:
busy = 1;
iframe->frame.data.padlen = iframe->buf[0];
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
iframe->frame.data.padlen <<= 8;
iframe->frame.data.padlen |= iframe->buf[1];
++iframe->frame.data.padlen;
}
++iframe->frame.data.padlen;
DEBUGF(fprintf(stderr, "padlen=%zu\n", iframe->frame.data.padlen));
if(iframe->frame.data.padlen > iframe->frame.hd.length) {
rv = inbound_frame_compute_pad(iframe);
if(rv < 0) {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
......@@ -3515,9 +3572,36 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
iframe->frame.data.padlen = rv;
iframe->state = NGHTTP2_IB_READ_DATA;
break;
case NGHTTP2_HEADERS:
if(iframe->padlen == 0 &&
iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) {
rv = inbound_frame_compute_pad(iframe);
if(rv < 0) {
busy = 1;
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
return rv;
}
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
iframe->frame.headers.padlen = rv;
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) {
if(iframe->payloadleft < 4) {
busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break;
}
iframe->state = NGHTTP2_IB_READ_NBYTE;
iframe->left = 4;
iframe->buflen = 0;
break;
}
}
rv = session_process_headers_frame(session);
if(nghttp2_is_fatal(rv)) {
return rv;
......@@ -3580,7 +3664,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
}
break;
case NGHTTP2_IB_READ_HEADER_BLOCK:
case NGHTTP2_IB_IGN_HEADER_BLOCK:
case NGHTTP2_IB_IGN_HEADER_BLOCK: {
ssize_t data_readlen;
#ifdef DEBUGBUILD
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
fprintf(stderr, "[IB_READ_HEADER_BLOCK]\n");
......@@ -3591,24 +3676,41 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
readlen = inbound_frame_payload_readlen(iframe, in, last);
DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft - readlen));
data_readlen = inbound_frame_effective_readlen
(iframe, iframe->payloadleft - readlen, readlen);
if(data_readlen >= 0) {
size_t trail_padlen;
size_t hd_proclen = 0;
trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame,
iframe->padlen);
DEBUGF(fprintf(stderr, "block final=%d\n",
(iframe->frame.hd.flags &
NGHTTP2_FLAG_END_HEADERS) &&
iframe->payloadleft == readlen));
rv = inflate_header_block(session, &iframe->frame, &readlen,
(uint8_t*)in, readlen,
iframe->payloadleft - data_readlen == trail_padlen));
rv = inflate_header_block
(session, &iframe->frame, &hd_proclen,
(uint8_t*)in, data_readlen,
(iframe->frame.hd.flags &
NGHTTP2_FLAG_END_HEADERS) &&
iframe->payloadleft == readlen,
iframe->payloadleft - data_readlen == trail_padlen,
iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK);
if(nghttp2_is_fatal(rv)) {
return rv;
}
in += readlen;
iframe->payloadleft -= readlen;
if(rv == NGHTTP2_ERR_PAUSE) {
in += hd_proclen;
iframe->payloadleft -= hd_proclen;
return in - first;
}
in += readlen;
iframe->payloadleft -= readlen;
if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
/* The application says no more headers. We decompress the
rest of the header block but not invoke on_header_callback
......@@ -3619,6 +3721,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) {
return rv;
}
busy = 1;
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
break;
}
......@@ -3627,32 +3730,40 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(iframe->payloadleft == 0) {
nghttp2_inbound_frame_reset(session);
} else {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
}
break;
}
} else {
in += readlen;
iframe->payloadleft -= readlen;
}
if(iframe->payloadleft) {
break;
}
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
rv = session_after_header_block_received(session);
if(nghttp2_is_fatal(rv)) {
return rv;
}
}
if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
iframe->left = NGHTTP2_FRAME_HEAD_LENGTH;
iframe->error_code = 0;
iframe->buflen = 0;
iframe->padlen = 0;
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION;
} else {
iframe->state = NGHTTP2_IB_IGN_CONTINUATION;
}
} else {
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
rv = session_after_header_block_received(session);
if(nghttp2_is_fatal(rv)) {
return rv;
}
}
nghttp2_inbound_frame_reset(session);
}
break;
}
case NGHTTP2_IB_IGN_PAYLOAD:
DEBUGF(fprintf(stderr, "[IB_IGN_PAYLOAD]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last);
......@@ -3761,9 +3872,30 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
if(cont_hd.flags & NGHTTP2_FLAG_END_HEADERS) {
iframe->frame.hd.flags |= NGHTTP2_FLAG_END_HEADERS;
iframe->frame.hd.flags |= cont_hd.flags &
(NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW);
rv = inbound_frame_handle_pad(iframe, &cont_hd);
if(rv < 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
return rv;
}
break;
}
if(rv == 1) {
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION;
} else {
iframe->state = NGHTTP2_IB_IGN_PAD_CONTINUATION;
}
break;
}
busy = 1;
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
......@@ -3771,6 +3903,46 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
}
break;
case NGHTTP2_IB_READ_PAD_CONTINUATION:
case NGHTTP2_IB_IGN_PAD_CONTINUATION:
#ifdef DEBUGBUILD
if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) {
fprintf(stderr, "[IB_READ_PAD_CONTINUATION]\n");
} else {
fprintf(stderr, "[IB_IGN_PAD_CONTINUATION]\n");
}
#endif /* DEBUGBUILD */
readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen;
iframe->payloadleft -= readlen;
DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu, left=%zu\n",
readlen, iframe->payloadleft, iframe->left));
if(iframe->left) {
return in - first;
}
busy = 1;
rv = inbound_frame_compute_pad(iframe);
if(rv < 0) {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
return rv;
}
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break;
}
iframe->padlen = rv;
if(iframe->frame.hd.type == NGHTTP2_HEADERS) {
iframe->frame.headers.padlen += rv;
} else {
iframe->frame.push_promise.padlen += rv;
}
if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
} else {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
}
break;
case NGHTTP2_IB_READ_DATA:
DEBUGF(fprintf(stderr, "[IB_READ_DATA]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last);
......@@ -3779,7 +3951,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft));
if(readlen > 0) {
size_t data_readlen = readlen;
ssize_t data_readlen;
rv = nghttp2_session_update_recv_connection_window_size
(session, readlen);
if(nghttp2_is_fatal(rv)) {
......@@ -3798,17 +3970,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
}
}
}
if(nghttp2_frame_data_trail_padlen(&iframe->frame.data) >
iframe->payloadleft) {
size_t trail_padlen;
trail_padlen = nghttp2_frame_data_trail_padlen(&iframe->frame.data)
- iframe->payloadleft;
if(readlen < trail_padlen) {
data_readlen = 0;
} else {
data_readlen -= trail_padlen;
}
}
data_readlen = inbound_frame_effective_readlen
(iframe, iframe->payloadleft, readlen);
DEBUGF(fprintf(stderr, "data_readlen=%zu\n", data_readlen));
if(data_readlen > 0 && session->callbacks.on_data_chunk_recv_callback) {
rv = session->callbacks.on_data_chunk_recv_callback
......@@ -4066,11 +4229,11 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW);
flags = 0;
if((session->opt_flags & NGHTTP2_OPTMASK_NO_DATA_PADDING) == 0 &&
if(session->pad_alignment &&
payloadlen > 0 && (size_t)payloadlen < datamax) {
rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr,
&flags, payloadlen, datamax,
session->data_pad_alignment);
session->pad_alignment);
if(rv < 0) {
return rv;
}
......
......@@ -44,10 +44,7 @@
*/
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1,
/* Option to disable DATA frame padding, which is currently hidden
from outside, but provided for ease of testing */
NGHTTP2_OPTMASK_NO_DATA_PADDING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1
} nghttp2_optmask;
typedef struct {
......@@ -89,6 +86,8 @@ typedef enum {
NGHTTP2_IB_READ_GOAWAY_DEBUG,
NGHTTP2_IB_EXPECT_CONTINUATION,
NGHTTP2_IB_IGN_CONTINUATION,
NGHTTP2_IB_READ_PAD_CONTINUATION,
NGHTTP2_IB_IGN_PAD_CONTINUATION,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state;
......@@ -105,6 +104,8 @@ typedef struct {
size_t left;
/* How many bytes we still need to receive for current frame */
size_t payloadleft;
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
/* TODO, remove this. Error code */
int error_code;
......@@ -152,8 +153,8 @@ struct nghttp2_session {
size_t num_incoming_streams;
/* The number of bytes allocated for nvbuf */
size_t nvbuflen;
/* DATA padding alignemnt. See NGHTTP2_OPT_DATA_PAD_ALIGNMENT. */
size_t data_pad_alignment;
/* padding alignemnt. See NGHTTP2_OPT_PAD_ALIGNMENT. */
size_t pad_alignment;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The largest stream ID received so far */
......
......@@ -66,7 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION;
Config::Config()
: data_ptr(nullptr),
output_upper_thres(1024*1024),
data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT),
pad_alignment(NGHTTP2_PAD_ALIGNMENT),
header_table_size(-1),
port(0),
verbose(false),
......@@ -365,11 +365,11 @@ int Http2Handler::on_connect()
nghttp2_opt_set opt_set;
memset(&opt_set, 0, sizeof(opt_set));
opt_set.data_pad_alignment = sessions_->get_config()->data_pad_alignment;
opt_set.pad_alignment = sessions_->get_config()->pad_alignment;
fill_callback(callbacks, sessions_->get_config());
r = nghttp2_session_server_new2(&session_, &callbacks, this,
NGHTTP2_OPT_DATA_PAD_ALIGNMENT, &opt_set);
NGHTTP2_OPT_PAD_ALIGNMENT, &opt_set);
if(r != 0) {
return r;
}
......
......@@ -56,7 +56,7 @@ struct Config {
std::string cert_file;
void *data_ptr;
size_t output_upper_thres;
size_t data_pad_alignment;
size_t pad_alignment;
ssize_t header_table_size;
uint16_t port;
bool verbose;
......
......@@ -244,6 +244,18 @@ void print_flags(const nghttp2_frame_hd& hd)
}
s += "PRIORITY";
}
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
if(!s.empty()) {
s += " | ";
}
s += "PAD_LOW";
}
if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
if(!s.empty()) {
s += " | ";
}
s += "PAD_HIGH";
}
break;
case NGHTTP2_SETTINGS:
if(hd.flags & NGHTTP2_FLAG_ACK) {
......@@ -254,6 +266,18 @@ void print_flags(const nghttp2_frame_hd& hd)
if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) {
s += "END_PUSH_PROMISE";
}
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
if(!s.empty()) {
s += " | ";
}
s += "PAD_LOW";
}
if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
if(!s.empty()) {
s += " | ";
}
s += "PAD_HIGH";
}
break;
case NGHTTP2_PING:
if(hd.flags & NGHTTP2_FLAG_ACK) {
......@@ -297,10 +321,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
}
break;
case NGHTTP2_HEADERS:
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
print_frame_attr_indent();
printf("(pri=%d)\n", frame->headers.pri);
}
printf("(pri=%d, padlen=%zu)\n",
frame->headers.pri, frame->headers.padlen);
switch(frame->headers.cat) {
case NGHTTP2_HCAT_REQUEST:
print_frame_attr_indent();
......@@ -342,8 +365,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
break;
case NGHTTP2_PUSH_PROMISE:
print_frame_attr_indent();
printf("(promised_stream_id=%d)\n",
frame->push_promise.promised_stream_id);
printf("(promised_stream_id=%d, padlen=%zu)\n",
frame->push_promise.promised_stream_id,
frame->push_promise.padlen);
print_nv(frame->push_promise.nva, frame->push_promise.nvlen);
break;
case NGHTTP2_PING:
......
......@@ -82,7 +82,7 @@ struct Config {
std::string keyfile;
std::string datafile;
size_t output_upper_thres;
size_t data_pad_alignment;
size_t pad_alignment;
ssize_t peer_max_concurrent_streams;
ssize_t header_table_size;
int32_t pri;
......@@ -100,7 +100,7 @@ struct Config {
bool continuation;
Config()
: output_upper_thres(1024*1024),
data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT),
pad_alignment(NGHTTP2_PAD_ALIGNMENT),
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
header_table_size(-1),
pri(NGHTTP2_PRI_DEFAULT),
......@@ -716,10 +716,10 @@ struct HttpClient {
}
nghttp2_opt_set opt_set;
opt_set.peer_max_concurrent_streams = config.peer_max_concurrent_streams;
opt_set.data_pad_alignment = config.data_pad_alignment;
opt_set.pad_alignment = config.pad_alignment;
rv = nghttp2_session_client_new2(&session, callbacks, this,
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS |
NGHTTP2_OPT_DATA_PAD_ALIGNMENT,
NGHTTP2_OPT_PAD_ALIGNMENT,
&opt_set);
if(rv != 0) {
return -1;
......@@ -1710,8 +1710,8 @@ void print_help(std::ostream& out)
<< " is large enough as it is seen as unlimited.\n"
<< " -c, --header-table-size=<N>\n"
<< " Specify decoder header table size.\n"
<< " -b, --data-pad=<ALIGNMENT>\n"
<< " Alignment of DATA frame padding.\n"
<< " -b, --pad=<ALIGNMENT>\n"
<< " Alignment of frame payload padding.\n"
<< " --color Force colored log output.\n"
<< " --continuation Send large header to test CONTINUATION.\n"
<< std::endl;
......@@ -1766,7 +1766,7 @@ int main(int argc, char **argv)
print_help(std::cout);
exit(EXIT_SUCCESS);
case 'b':
config.data_pad_alignment = strtol(optarg, nullptr, 10);
config.pad_alignment = strtol(optarg, nullptr, 10);
break;
case 'n':
config.null_out = true;
......
......@@ -115,8 +115,8 @@ void print_help(std::ostream& out)
<< " -p/=/foo.png -p/doc=/bar.css\n"
<< " PATH and PUSH_PATHs are relative to document\n"
<< " root. See --htdocs option.\n"
<< " -b, --data-pad=<ALIGNMENT>\n"
<< " Alignment of DATA frame padding.\n"
<< " -b, --pad=<ALIGNMENT>\n"
<< " Alignment of frame payload padding.\n"
<< " -h, --help Print this help.\n"
<< std::endl;
}
......@@ -155,7 +155,7 @@ int main(int argc, char **argv)
config.verify_client = true;
break;
case 'b':
config.data_pad_alignment = strtol(optarg, nullptr, 10);
config.pad_alignment = strtol(optarg, nullptr, 10);
break;
case 'd':
config.htdocs = optarg;
......
......@@ -74,6 +74,7 @@ void test_nghttp2_frame_pack_headers()
nghttp2_headers frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t bufoff;
ssize_t framelen;
nghttp2_nv *nva;
ssize_t nvlen;
......@@ -89,17 +90,21 @@ 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, &frame, &deflater);
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
&deflater, 0);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS,
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
framelen - bufoff));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
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);
CU_ASSERT(framelen - 8 ==
inflate_hd(&inflater, &out, buf + 8, framelen - 8));
CU_ASSERT(framelen - (ssize_t)bufoff - 8 ==
inflate_hd(&inflater, &out,
buf + bufoff + 8, framelen - bufoff - 8));
CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
......@@ -111,10 +116,13 @@ void test_nghttp2_frame_pack_headers()
memset(&oframe, 0, sizeof(oframe));
/* Next, include PRIORITY flag */
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater);
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
&deflater, 0);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS,
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff,
framelen - bufoff));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY,
1000000007, &oframe.hd);
......@@ -140,6 +148,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
nghttp2_headers frame;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t bufoff;
ssize_t framelen;
nghttp2_nv *nva;
ssize_t nvlen;
......@@ -163,7 +172,8 @@ 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, &frame, &deflater);
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame,
&deflater, 0);
CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen);
nghttp2_frame_headers_free(&frame);
......
......@@ -336,9 +336,10 @@ void test_nghttp2_session_recv(void)
};
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen;
nghttp2_frame frame;
int i;
size_t i;
nghttp2_outbound_item *item;
nghttp2_nv *nva;
ssize_t nvlen;
......@@ -355,13 +356,13 @@ void test_nghttp2_session_recv(void)
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen,
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
scripted_data_feed_init(&df, framedata, framelen);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
/* Send 1 byte per each read */
for(i = 0; i < framelen; ++i) {
for(i = 0; i < framelen - bufoff; ++i) {
df.feedseq[i] = 1;
}
nghttp2_frame_headers_free(&frame.headers);
......@@ -375,13 +376,13 @@ void test_nghttp2_session_recv(void)
/* 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,
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
nghttp2_frame_headers_free(&frame.headers);
scripted_data_feed_init(&df, framedata, framelen);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.frame_recv_cb_called);
......@@ -421,6 +422,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
my_user_data user_data;
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen;
nghttp2_frame frame;
nghttp2_hd_deflater deflater;
......@@ -436,11 +438,11 @@ 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,
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
scripted_data_feed_init(&df, framedata, framelen);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
nghttp2_frame_headers_free(&frame.headers);
CU_ASSERT(0 == nghttp2_session_recv(session));
......@@ -462,6 +464,7 @@ void test_nghttp2_session_recv_invalid_frame(void)
};
uint8_t *framedata = NULL;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen;
nghttp2_frame frame;
nghttp2_nv *nva;
......@@ -480,11 +483,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,
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
scripted_data_feed_init(&df, framedata, framelen);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
......@@ -492,7 +495,7 @@ 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, framelen);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session));
......@@ -660,6 +663,7 @@ void test_nghttp2_session_recv_continuation(void)
uint8_t *framedata = NULL;
size_t framedatacap = 0;
size_t framedatalen;
size_t bufoff;
size_t framedataoff;
ssize_t rv;
my_user_data ud;
......@@ -681,13 +685,14 @@ void test_nghttp2_session_recv_continuation(void)
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);
&deflater, 0);
nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata, 9);
memcpy(data, framedata + bufoff, 9);
datalen = 9;
framedataoff = NGHTTP2_FRAME_HEAD_LENGTH + 1;
framedataoff = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 1;
nghttp2_put_uint16be(data, 1);
......@@ -735,12 +740,12 @@ 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,
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata, framedatalen);
datalen = framedatalen;
memcpy(data, framedata + bufoff, framedatalen - bufoff);
datalen = framedatalen - bufoff;
/* Followed by PRIORITY */
nghttp2_frame_priority_init(&frame.priority, 1, 0);
......@@ -782,6 +787,7 @@ void test_nghttp2_session_continue(void)
uint8_t buffer[4096];
uint8_t *bufp = buffer;
size_t buflen;
size_t bufoff;
nghttp2_frame frame;
nghttp2_nv *nva;
ssize_t nvlen;
......@@ -804,22 +810,24 @@ 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,
framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer, framedata, framelen1);
memcpy(buffer, framedata + bufoff, framelen1 - bufoff);
framelen1 -= bufoff;
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,
framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff,
&frame.headers,
&deflater);
&deflater, 0);
nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer + framelen1, framedata, framelen2);
memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff);
framelen2 -= bufoff;
buflen = framelen1 + framelen2;
/* Receive 1st HEADERS and pause */
......@@ -955,6 +963,7 @@ void test_nghttp2_session_add_frame(void)
acc.length = 0;
user_data.acc = &acc;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data));
session_disable_pad(session);
frame = malloc(sizeof(nghttp2_frame));
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
......@@ -2173,6 +2182,7 @@ void test_nghttp2_submit_request_without_data(void)
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
session_disable_pad(session);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), &data_prd, NULL));
......@@ -2244,6 +2254,7 @@ void test_nghttp2_submit_response_without_data(void)
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
session_disable_pad(session);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE);
nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM,
NGHTTP2_PRI_DEFAULT,
......@@ -2415,6 +2426,7 @@ void test_nghttp2_submit_headers(void)
callbacks.on_frame_send_callback = on_frame_send_callback;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
session_disable_pad(session);
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST);
CU_ASSERT(0 == nghttp2_submit_headers(session,
NGHTTP2_FLAG_END_STREAM,
......@@ -3858,7 +3870,7 @@ void test_nghttp2_session_pack_data_with_padding(void)
data_prd.read_callback = fixed_length_data_source_read_callback;
nghttp2_session_client_new(&session, &callbacks, &ud);
session->data_pad_alignment = 512;
session->pad_alignment = 512;
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd,
NULL);
......@@ -3869,7 +3881,7 @@ void test_nghttp2_session_pack_data_with_padding(void)
CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
frame = OB_DATA(session->aob.item);
CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen);
CU_ASSERT(session->pad_alignment - datalen == frame->padlen);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH);
......@@ -3893,7 +3905,7 @@ void test_nghttp2_session_pack_data_with_padding(void)
CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
frame = OB_DATA(session->aob.item);
CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen);
CU_ASSERT(session->pad_alignment - datalen == frame->padlen);
CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW);
CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH));
......
......@@ -159,3 +159,8 @@ ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
nghttp2_hd_inflate_end_headers(inflater);
return initial - buflen;
}
void session_disable_pad(nghttp2_session *session)
{
session->pad_alignment = 0;
}
......@@ -29,6 +29,7 @@
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include "nghttp2_session.h"
#include "nghttp2_frame.h"
#include "nghttp2_hd.h"
......@@ -57,4 +58,6 @@ void add_out(nva_out *out, nghttp2_nv *nv);
ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
uint8_t *buf, size_t buflen);
void session_disable_pad(nghttp2_session *session);
#endif /* NGHTTP2_TEST_HELPER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment