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:
Tatsuhiro Tsujikawa 2014-01-26 22:01:27 +09:00
parent 91401cfe26
commit 9314e30987
12 changed files with 157 additions and 66 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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. */

View File

@ -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();

View File

@ -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) ||

View File

@ -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;

View File

@ -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;

View File

@ -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);