Support transmission of CONTINUATION, change nghttp2_frame_hd
The maximum frame size including header block is still limited to NGHTTP2_HD_MAX_BUFFER_LENGTH, which is 32KB.
This commit is contained in:
parent
91401cfe26
commit
9314e30987
|
@ -504,7 +504,11 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* The length field of this frame, excluding frame header.
|
* The length field of this frame, excluding frame header.
|
||||||
*/
|
*/
|
||||||
uint16_t length;
|
size_t length;
|
||||||
|
/**
|
||||||
|
* The stream identifier (aka, stream ID)
|
||||||
|
*/
|
||||||
|
int32_t stream_id;
|
||||||
/**
|
/**
|
||||||
* The type of this frame. See `nghttp2_frame`.
|
* The type of this frame. See `nghttp2_frame`.
|
||||||
*/
|
*/
|
||||||
|
@ -513,10 +517,6 @@ typedef struct {
|
||||||
* The flags.
|
* The flags.
|
||||||
*/
|
*/
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
/**
|
|
||||||
* The stream identifier (aka, stream ID)
|
|
||||||
*/
|
|
||||||
int32_t stream_id;
|
|
||||||
} nghttp2_frame_hd;
|
} nghttp2_frame_hd;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,12 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
framelen = rv + nv_offset;
|
framelen = rv + nv_offset;
|
||||||
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
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;
|
||||||
|
} else {
|
||||||
|
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||||
|
}
|
||||||
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
||||||
nv_offset */
|
nv_offset */
|
||||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
||||||
|
@ -387,7 +392,12 @@ ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
framelen = rv + nv_offset;
|
framelen = rv + nv_offset;
|
||||||
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
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;
|
||||||
|
} else {
|
||||||
|
frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||||
|
}
|
||||||
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
|
||||||
nv_offset */
|
nv_offset */
|
||||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset);
|
||||||
|
@ -562,8 +572,8 @@ ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
nghttp2_nv *p;
|
nghttp2_nv *p;
|
||||||
for(i = 0; i < nvlen; ++i) {
|
for(i = 0; i < nvlen; ++i) {
|
||||||
if(nva[i].namelen > NGHTTP2_MAX_HD_VALUE_LENGTH ||
|
if(nva[i].namelen > NGHTTP2_HD_MAX_NAME ||
|
||||||
nva[i].valuelen > NGHTTP2_MAX_HD_VALUE_LENGTH) {
|
nva[i].valuelen > NGHTTP2_HD_MAX_VALUE) {
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
buflen += nva[i].namelen + nva[i].valuelen;
|
buflen += nva[i].namelen + nva[i].valuelen;
|
||||||
|
|
|
@ -33,10 +33,6 @@
|
||||||
#include "nghttp2_hd.h"
|
#include "nghttp2_hd.h"
|
||||||
#include "nghttp2_buffer.h"
|
#include "nghttp2_buffer.h"
|
||||||
|
|
||||||
/* The maximum value length of name/value pair. This is not specified
|
|
||||||
by the spec. We just chose the arbitrary size */
|
|
||||||
#define NGHTTP2_MAX_HD_VALUE_LENGTH ((1 << 13) - 1)
|
|
||||||
|
|
||||||
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
|
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
|
||||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||||
|
@ -99,7 +95,10 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
|
||||||
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
|
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
|
||||||
*
|
*
|
||||||
* frame->hd.length is assigned after length is determined during
|
* frame->hd.length is assigned after length is determined during
|
||||||
* packing process.
|
* 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
|
* This function returns the size of packed frame if it succeeds, or
|
||||||
* returns one of the following negative error codes:
|
* returns one of the following negative error codes:
|
||||||
|
@ -242,7 +241,10 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||||
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
|
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
|
||||||
*
|
*
|
||||||
* frame->hd.length is assigned after length is determined during
|
* frame->hd.length is assigned after length is determined during
|
||||||
* packing process.
|
* 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
|
* This function returns the size of packed frame if it succeeds, or
|
||||||
* returns one of the following negative error codes:
|
* returns one of the following negative error codes:
|
||||||
|
|
|
@ -443,9 +443,7 @@ static int ensure_write_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
size_t offset, size_t need)
|
size_t offset, size_t need)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
/* TODO Remove this limitation when header continuation is
|
if(need + offset > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
|
||||||
implemented. */
|
|
||||||
if(need + offset > NGHTTP2_MAX_FRAME_LENGTH) {
|
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
}
|
}
|
||||||
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
|
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
|
||||||
|
|
|
@ -37,8 +37,11 @@
|
||||||
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE (1 << 12)
|
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE (1 << 12)
|
||||||
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
|
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
|
||||||
|
|
||||||
|
/* The maximum value length of name/value pair. This is not specified
|
||||||
|
by the spec. We just chose the arbitrary size */
|
||||||
#define NGHTTP2_HD_MAX_NAME 256
|
#define NGHTTP2_HD_MAX_NAME 256
|
||||||
#define NGHTTP2_HD_MAX_VALUE 4096
|
#define NGHTTP2_HD_MAX_VALUE 4096
|
||||||
|
#define NGHTTP2_HD_MAX_BUFFER_LENGTH (1 << 15)
|
||||||
|
|
||||||
/* Default size of maximum table buffer size for encoder. Even if
|
/* Default size of maximum table buffer size for encoder. Even if
|
||||||
remote decoder notifies larger buffer size for its decoding,
|
remote decoder notifies larger buffer size for its decoding,
|
||||||
|
|
|
@ -384,7 +384,7 @@ static void nghttp2_active_outbound_item_reset
|
||||||
nghttp2_outbound_item_free(aob->item);
|
nghttp2_outbound_item_free(aob->item);
|
||||||
free(aob->item);
|
free(aob->item);
|
||||||
aob->item = NULL;
|
aob->item = NULL;
|
||||||
aob->framebuflen = aob->framebufoff = 0;
|
aob->framebuflen = aob->framebufoff = aob->framebufmark = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_session_del(nghttp2_session *session)
|
void nghttp2_session_del(nghttp2_session *session)
|
||||||
|
@ -1405,6 +1405,32 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
|
||||||
int r;
|
int r;
|
||||||
nghttp2_frame *frame;
|
nghttp2_frame *frame;
|
||||||
frame = nghttp2_outbound_item_get_ctrl_frame(session->aob.item);
|
frame = nghttp2_outbound_item_get_ctrl_frame(session->aob.item);
|
||||||
|
if(frame->hd.type == NGHTTP2_HEADERS ||
|
||||||
|
frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||||
|
if(session->aob.framebufmark < session->aob.framebuflen) {
|
||||||
|
nghttp2_frame_hd cont_hd;
|
||||||
|
cont_hd.length = nghttp2_min(session->aob.framebuflen -
|
||||||
|
session->aob.framebufmark,
|
||||||
|
NGHTTP2_MAX_FRAME_LENGTH);
|
||||||
|
cont_hd.type = NGHTTP2_CONTINUATION;
|
||||||
|
if(cont_hd.length < NGHTTP2_MAX_FRAME_LENGTH) {
|
||||||
|
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
|
||||||
|
} else {
|
||||||
|
cont_hd.flags = NGHTTP2_FLAG_NONE;
|
||||||
|
}
|
||||||
|
cont_hd.stream_id = frame->hd.stream_id;
|
||||||
|
nghttp2_frame_pack_frame_hd(session->aob.framebuf +
|
||||||
|
session->aob.framebufmark -
|
||||||
|
NGHTTP2_FRAME_HEAD_LENGTH,
|
||||||
|
&cont_hd);
|
||||||
|
session->aob.framebufmark += cont_hd.length;
|
||||||
|
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;
|
||||||
|
}
|
||||||
if(session->callbacks.on_frame_send_callback) {
|
if(session->callbacks.on_frame_send_callback) {
|
||||||
if(session->callbacks.on_frame_send_callback(session, frame,
|
if(session->callbacks.on_frame_send_callback(session, frame,
|
||||||
session->user_data) != 0) {
|
session->user_data) != 0) {
|
||||||
|
@ -1623,7 +1649,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
|
||||||
nghttp2_active_outbound_item_reset(&session->aob);
|
nghttp2_active_outbound_item_reset(&session->aob);
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
session->aob.framebuflen = r;
|
session->aob.framebuflen = session->aob.framebufmark = r;
|
||||||
session->aob.framebufoff = 0;
|
session->aob.framebufoff = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1666,7 +1692,8 @@ int nghttp2_session_send(nghttp2_session *session)
|
||||||
framebuflen = nghttp2_session_prep_frame(session, item);
|
framebuflen = nghttp2_session_prep_frame(session, item);
|
||||||
if(framebuflen == NGHTTP2_ERR_DEFERRED) {
|
if(framebuflen == NGHTTP2_ERR_DEFERRED) {
|
||||||
continue;
|
continue;
|
||||||
} else if(framebuflen < 0) {
|
}
|
||||||
|
if(framebuflen < 0) {
|
||||||
/* TODO If the error comes from compressor, the connection
|
/* TODO If the error comes from compressor, the connection
|
||||||
must be closed. */
|
must be closed. */
|
||||||
if(item->frame_cat == NGHTTP2_CAT_CTRL &&
|
if(item->frame_cat == NGHTTP2_CAT_CTRL &&
|
||||||
|
@ -1700,19 +1727,31 @@ int nghttp2_session_send(nghttp2_session *session)
|
||||||
}
|
}
|
||||||
session->aob.item = item;
|
session->aob.item = item;
|
||||||
session->aob.framebuflen = framebuflen;
|
session->aob.framebuflen = framebuflen;
|
||||||
/* Call before_send callback */
|
|
||||||
if(item->frame_cat == NGHTTP2_CAT_CTRL &&
|
if(item->frame_cat == NGHTTP2_CAT_CTRL) {
|
||||||
session->callbacks.before_frame_send_callback) {
|
nghttp2_frame *frame = nghttp2_outbound_item_get_ctrl_frame(item);
|
||||||
if(session->callbacks.before_frame_send_callback
|
session->aob.framebufmark =
|
||||||
(session,
|
frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH;
|
||||||
nghttp2_outbound_item_get_ctrl_frame(item),
|
/* Call before_send callback */
|
||||||
session->user_data) != 0) {
|
if(session->callbacks.before_frame_send_callback) {
|
||||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
size_t origlen = frame->hd.length;
|
||||||
|
frame->hd.length =
|
||||||
|
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH;
|
||||||
|
r = session->callbacks.before_frame_send_callback
|
||||||
|
(session, frame, session->user_data);
|
||||||
|
frame->hd.length = origlen;
|
||||||
|
if(r != 0) {
|
||||||
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
session->aob.framebufmark =
|
||||||
|
nghttp2_outbound_item_get_data_frame
|
||||||
|
(session->aob.item)->hd.length + NGHTTP2_FRAME_HEAD_LENGTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data = session->aob.framebuf + session->aob.framebufoff;
|
data = session->aob.framebuf + session->aob.framebufoff;
|
||||||
datalen = session->aob.framebuflen - session->aob.framebufoff;
|
datalen = session->aob.framebufmark - session->aob.framebufoff;
|
||||||
sentlen = session->callbacks.send_callback(session, data, datalen, 0,
|
sentlen = session->callbacks.send_callback(session, data, datalen, 0,
|
||||||
session->user_data);
|
session->user_data);
|
||||||
if(sentlen < 0) {
|
if(sentlen < 0) {
|
||||||
|
@ -1742,7 +1781,7 @@ int nghttp2_session_send(nghttp2_session *session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session->aob.framebufoff += sentlen;
|
session->aob.framebufoff += sentlen;
|
||||||
if(session->aob.framebufoff == session->aob.framebuflen) {
|
if(session->aob.framebufoff == session->aob.framebufmark) {
|
||||||
/* Frame has completely sent */
|
/* Frame has completely sent */
|
||||||
r = nghttp2_session_after_frame_sent(session);
|
r = nghttp2_session_after_frame_sent(session);
|
||||||
if(r < 0) {
|
if(r < 0) {
|
||||||
|
@ -1823,6 +1862,8 @@ static int session_call_on_end_headers
|
||||||
(nghttp2_session *session, nghttp2_frame *frame, nghttp2_error_code error_code)
|
(nghttp2_session *session, nghttp2_frame *frame, nghttp2_error_code error_code)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
DEBUGF(fprintf(stderr, "Call on_end_headers callback stream_id=%d\n",
|
||||||
|
frame->hd.stream_id));
|
||||||
if(session->callbacks.on_end_headers_callback) {
|
if(session->callbacks.on_end_headers_callback) {
|
||||||
rv = session->callbacks.on_end_headers_callback(session, frame, error_code,
|
rv = session->callbacks.on_end_headers_callback(session, frame, error_code,
|
||||||
session->user_data);
|
session->user_data);
|
||||||
|
@ -2167,11 +2208,6 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
/* Connection error if header continuation is employed for now */
|
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
|
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
|
||||||
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
if(session->goaway_flags) {
|
if(session->goaway_flags) {
|
||||||
/* We don't accept new stream after GOAWAY is sent or received. */
|
/* We don't accept new stream after GOAWAY is sent or received. */
|
||||||
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
|
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
|
||||||
|
@ -2222,11 +2258,6 @@ int nghttp2_session_on_response_headers_received(nghttp2_session *session,
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
/* Connection error if header continuation is employed for now */
|
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
|
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
|
||||||
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
if(stream->shut_flags & NGHTTP2_SHUT_RD) {
|
if(stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||||
/* half closed (remote): from the spec:
|
/* half closed (remote): from the spec:
|
||||||
|
|
||||||
|
@ -2255,11 +2286,6 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
/* Connection error if header continuation is employed for now */
|
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
|
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
|
||||||
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
if(session->goaway_flags) {
|
if(session->goaway_flags) {
|
||||||
/* We don't accept new stream after GOAWAY is sent or received. */
|
/* We don't accept new stream after GOAWAY is sent or received. */
|
||||||
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
|
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
|
||||||
|
@ -2286,11 +2312,6 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
/* Connection error if header continuation is employed for now */
|
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
|
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
|
||||||
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
if(stream->state == NGHTTP2_STREAM_RESERVED) {
|
if(stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||||
/* reserved. The valid push response HEADERS is processed by
|
/* reserved. The valid push response HEADERS is processed by
|
||||||
nghttp2_session_on_push_response_headers_received(). This
|
nghttp2_session_on_push_response_headers_received(). This
|
||||||
|
@ -2848,11 +2869,6 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
/* Connection error if header continuation is employed for now */
|
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) == 0) {
|
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
|
||||||
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
if(session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) {
|
if(session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) {
|
||||||
return nghttp2_session_inflate_handle_invalid_connection
|
return nghttp2_session_inflate_handle_invalid_connection
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
@ -3601,6 +3617,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
||||||
DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n",
|
DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n",
|
||||||
readlen, iframe->payloadleft));
|
readlen, iframe->payloadleft));
|
||||||
|
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,
|
rv = inflate_header_block(session, &iframe->frame, &readlen,
|
||||||
(uint8_t*)in, readlen,
|
(uint8_t*)in, readlen,
|
||||||
(iframe->frame.hd.flags &
|
(iframe->frame.hd.flags &
|
||||||
|
@ -3730,6 +3750,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
iframe->payloadleft = cont_hd.length;
|
iframe->payloadleft = cont_hd.length;
|
||||||
if(cont_hd.type != NGHTTP2_CONTINUATION ||
|
if(cont_hd.type != NGHTTP2_CONTINUATION ||
|
||||||
cont_hd.stream_id != iframe->frame.hd.stream_id) {
|
cont_hd.stream_id != iframe->frame.hd.stream_id) {
|
||||||
|
DEBUGF(fprintf(stderr, "expected stream_id=%d, type=%d, but "
|
||||||
|
"got stream_id=%d, type=%d\n",
|
||||||
|
iframe->frame.hd.stream_id, NGHTTP2_CONTINUATION,
|
||||||
|
cont_hd.stream_id, cont_hd.type));
|
||||||
rv = nghttp2_session_terminate_session(session,
|
rv = nghttp2_session_terminate_session(session,
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
@ -4024,6 +4048,7 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
|
||||||
/* This is the error code when callback is failed. */
|
/* This is the error code when callback is failed. */
|
||||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||||
}
|
}
|
||||||
|
frame->hd.length = r;
|
||||||
memset(*buf_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
|
memset(*buf_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
|
||||||
nghttp2_put_uint16be(&(*buf_ptr)[0], r);
|
nghttp2_put_uint16be(&(*buf_ptr)[0], r);
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
|
@ -60,6 +60,9 @@ typedef struct {
|
||||||
size_t framebuflen;
|
size_t framebuflen;
|
||||||
/* The number of bytes has been sent */
|
/* The number of bytes has been sent */
|
||||||
size_t framebufoff;
|
size_t framebufoff;
|
||||||
|
/* Marks the last position to send. This is used to implement
|
||||||
|
CONTINUATION */
|
||||||
|
size_t framebufmark;
|
||||||
} nghttp2_active_outbound_item;
|
} nghttp2_active_outbound_item;
|
||||||
|
|
||||||
/* Buffer length for inbound raw byte stream. */
|
/* Buffer length for inbound raw byte stream. */
|
||||||
|
|
|
@ -438,7 +438,7 @@ void print_data_frame(print_type ptype, uint16_t length, uint8_t flags,
|
||||||
{
|
{
|
||||||
printf("%sDATA%s frame ",
|
printf("%sDATA%s frame ",
|
||||||
frame_name_ansi_esc(ptype), ansi_escend());
|
frame_name_ansi_esc(ptype), ansi_escend());
|
||||||
nghttp2_frame_hd hd = {length, NGHTTP2_DATA, flags, stream_id};
|
nghttp2_frame_hd hd = {length, stream_id, NGHTTP2_DATA, flags};
|
||||||
print_frame_hd(hd);
|
print_frame_hd(hd);
|
||||||
if(flags) {
|
if(flags) {
|
||||||
print_frame_attr_indent();
|
print_frame_attr_indent();
|
||||||
|
|
|
@ -144,6 +144,8 @@ int main(int argc, char* argv[])
|
||||||
!CU_add_test(pSuite, "submit_headers_push_reply",
|
!CU_add_test(pSuite, "submit_headers_push_reply",
|
||||||
test_nghttp2_submit_headers_push_reply) ||
|
test_nghttp2_submit_headers_push_reply) ||
|
||||||
!CU_add_test(pSuite, "submit_headers", test_nghttp2_submit_headers) ||
|
!CU_add_test(pSuite, "submit_headers", test_nghttp2_submit_headers) ||
|
||||||
|
!CU_add_test(pSuite, "submit_headers_continuation",
|
||||||
|
test_nghttp2_submit_headers_continuation) ||
|
||||||
!CU_add_test(pSuite, "submit_priority", test_nghttp2_submit_priority) ||
|
!CU_add_test(pSuite, "submit_priority", test_nghttp2_submit_priority) ||
|
||||||
!CU_add_test(pSuite, "session_submit_settings",
|
!CU_add_test(pSuite, "session_submit_settings",
|
||||||
test_nghttp2_submit_settings) ||
|
test_nghttp2_submit_settings) ||
|
||||||
|
|
|
@ -143,8 +143,8 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
|
||||||
ssize_t framelen;
|
ssize_t framelen;
|
||||||
nghttp2_nv *nva;
|
nghttp2_nv *nva;
|
||||||
ssize_t nvlen;
|
ssize_t nvlen;
|
||||||
size_t big_vallen = NGHTTP2_MAX_HD_VALUE_LENGTH;
|
size_t big_vallen = NGHTTP2_HD_MAX_VALUE;
|
||||||
nghttp2_nv big_hds[8];
|
nghttp2_nv big_hds[16];
|
||||||
size_t big_hdslen = ARRLEN(big_hds);
|
size_t big_hdslen = ARRLEN(big_hds);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
|
|
@ -734,7 +734,7 @@ void test_nghttp2_session_recv_continuation(void)
|
||||||
|
|
||||||
ud.header_cb_called = 0;
|
ud.header_cb_called = 0;
|
||||||
rv = nghttp2_session_mem_recv(session, data, datalen);
|
rv = nghttp2_session_mem_recv(session, data, datalen);
|
||||||
CU_ASSERT(rv == datalen);
|
CU_ASSERT((ssize_t)datalen == rv);
|
||||||
CU_ASSERT(2 == ud.header_cb_called);
|
CU_ASSERT(2 == ud.header_cb_called);
|
||||||
|
|
||||||
nghttp2_hd_deflate_free(&deflater);
|
nghttp2_hd_deflate_free(&deflater);
|
||||||
|
@ -765,7 +765,7 @@ void test_nghttp2_session_recv_continuation(void)
|
||||||
|
|
||||||
ud.end_headers_cb_called = 0;
|
ud.end_headers_cb_called = 0;
|
||||||
rv = nghttp2_session_mem_recv(session, data, datalen);
|
rv = nghttp2_session_mem_recv(session, data, datalen);
|
||||||
CU_ASSERT(datalen == rv);
|
CU_ASSERT((ssize_t)datalen == rv);
|
||||||
|
|
||||||
CU_ASSERT(1 == ud.end_headers_cb_called);
|
CU_ASSERT(1 == ud.end_headers_cb_called);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY ==
|
CU_ASSERT(NGHTTP2_GOAWAY ==
|
||||||
|
@ -847,7 +847,8 @@ void test_nghttp2_session_continue(void)
|
||||||
|
|
||||||
recv_frame = user_data.frame;
|
recv_frame = user_data.frame;
|
||||||
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
|
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
|
||||||
CU_ASSERT(framelen1 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
|
CU_ASSERT((size_t)framelen1 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
||||||
|
recv_frame->hd.length);
|
||||||
|
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(0 == user_data.end_headers_cb_called);
|
CU_ASSERT(0 == user_data.end_headers_cb_called);
|
||||||
|
@ -877,7 +878,8 @@ void test_nghttp2_session_continue(void)
|
||||||
|
|
||||||
recv_frame = user_data.frame;
|
recv_frame = user_data.frame;
|
||||||
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
|
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
|
||||||
CU_ASSERT(framelen2 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
|
CU_ASSERT((size_t)framelen2 - NGHTTP2_FRAME_HEAD_LENGTH ==
|
||||||
|
recv_frame->hd.length);
|
||||||
|
|
||||||
CU_ASSERT(1 == user_data.header_cb_called);
|
CU_ASSERT(1 == user_data.header_cb_called);
|
||||||
CU_ASSERT(1 == user_data.end_headers_cb_called);
|
CU_ASSERT(1 == user_data.end_headers_cb_called);
|
||||||
|
@ -1801,7 +1803,6 @@ void test_nghttp2_session_send_headers_reply(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Rewrite this test when header continuation is supported */
|
|
||||||
void test_nghttp2_session_send_headers_header_comp_error(void)
|
void test_nghttp2_session_send_headers_header_comp_error(void)
|
||||||
{
|
{
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
|
@ -1809,8 +1810,8 @@ void test_nghttp2_session_send_headers_header_comp_error(void)
|
||||||
nghttp2_frame *frame = malloc(sizeof(nghttp2_frame));
|
nghttp2_frame *frame = malloc(sizeof(nghttp2_frame));
|
||||||
nghttp2_nv *nva;
|
nghttp2_nv *nva;
|
||||||
ssize_t nvlen;
|
ssize_t nvlen;
|
||||||
size_t vallen = NGHTTP2_MAX_HD_VALUE_LENGTH;
|
size_t vallen = NGHTTP2_HD_MAX_VALUE;
|
||||||
nghttp2_nv nv[8];
|
nghttp2_nv nv[16];
|
||||||
size_t nnv = ARRLEN(nv);
|
size_t nnv = ARRLEN(nv);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -2455,6 +2456,52 @@ void test_nghttp2_submit_headers(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_submit_headers_continuation(void)
|
||||||
|
{
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
nghttp2_nv nv[] = {
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
MAKE_NV("h1", ""),
|
||||||
|
};
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
uint8_t data[4096];
|
||||||
|
size_t i;
|
||||||
|
my_user_data ud;
|
||||||
|
|
||||||
|
memset(data, '0', sizeof(data));
|
||||||
|
for(i = 0; i < ARRLEN(nv); ++i) {
|
||||||
|
nv[i].valuelen = sizeof(data);
|
||||||
|
nv[i].value = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
callbacks.send_callback = null_send_callback;
|
||||||
|
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
|
||||||
|
CU_ASSERT(0 == nghttp2_submit_headers(session,
|
||||||
|
NGHTTP2_FLAG_END_STREAM,
|
||||||
|
-1, NGHTTP2_PRI_DEFAULT,
|
||||||
|
nv, ARRLEN(nv), NULL));
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
CU_ASSERT(NGHTTP2_HEADERS == OB_CTRL_TYPE(item));
|
||||||
|
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) ==
|
||||||
|
OB_CTRL(item)->hd.flags);
|
||||||
|
CU_ASSERT(NGHTTP2_PRI_DEFAULT == OB_CTRL(item)->headers.pri);
|
||||||
|
|
||||||
|
ud.frame_send_cb_called = 0;
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(1 == ud.frame_send_cb_called);
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_submit_priority(void)
|
void test_nghttp2_submit_priority(void)
|
||||||
{
|
{
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
|
|
|
@ -62,6 +62,7 @@ void test_nghttp2_submit_headers_start_stream(void);
|
||||||
void test_nghttp2_submit_headers_reply(void);
|
void test_nghttp2_submit_headers_reply(void);
|
||||||
void test_nghttp2_submit_headers_push_reply(void);
|
void test_nghttp2_submit_headers_push_reply(void);
|
||||||
void test_nghttp2_submit_headers(void);
|
void test_nghttp2_submit_headers(void);
|
||||||
|
void test_nghttp2_submit_headers_continuation(void);
|
||||||
void test_nghttp2_submit_priority(void);
|
void test_nghttp2_submit_priority(void);
|
||||||
void test_nghttp2_submit_settings(void);
|
void test_nghttp2_submit_settings(void);
|
||||||
void test_nghttp2_submit_settings_update_local_window_size(void);
|
void test_nghttp2_submit_settings_update_local_window_size(void);
|
||||||
|
|
Loading…
Reference in New Issue