Implement padding for HEADERS and CONTINUATION
This commit is contained in:
parent
10feab02e8
commit
1db2195389
|
@ -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(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri);
|
||||
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);
|
||||
}
|
||||
return framelen;
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri);
|
||||
}
|
||||
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,68 +3676,94 @@ 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));
|
||||
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->frame.hd.flags &
|
||||
NGHTTP2_FLAG_END_HEADERS) &&
|
||||
iframe->payloadleft == readlen,
|
||||
iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
in += readlen;
|
||||
iframe->payloadleft -= readlen;
|
||||
if(rv == NGHTTP2_ERR_PAUSE) {
|
||||
return in - first;
|
||||
}
|
||||
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
|
||||
and on_frame_recv_callback. */
|
||||
rv = nghttp2_session_add_rst_stream(session,
|
||||
iframe->frame.hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
|
||||
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 - 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 - data_readlen == trail_padlen,
|
||||
iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
||||
break;
|
||||
}
|
||||
if(rv == NGHTTP2_ERR_HEADER_COMP) {
|
||||
/* GOAWAY is already issued */
|
||||
if(iframe->payloadleft == 0) {
|
||||
nghttp2_inbound_frame_reset(session);
|
||||
} else {
|
||||
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||
|
||||
if(rv == NGHTTP2_ERR_PAUSE) {
|
||||
in += hd_proclen;
|
||||
iframe->payloadleft -= hd_proclen;
|
||||
|
||||
return in - first;
|
||||
}
|
||||
break;
|
||||
|
||||
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
|
||||
and on_frame_recv_callback. */
|
||||
rv = nghttp2_session_add_rst_stream(session,
|
||||
iframe->frame.hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
busy = 1;
|
||||
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
||||
break;
|
||||
}
|
||||
if(rv == NGHTTP2_ERR_HEADER_COMP) {
|
||||
/* GOAWAY is already issued */
|
||||
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);
|
||||
}
|
||||
print_frame_attr_indent();
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue