Apply initiated SETTINGS changes on reception of ACK
This commit is contained in:
parent
2afa9f75f5
commit
a46ccdb144
|
@ -127,6 +127,13 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 16) - 1)
|
#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 16) - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro
|
||||||
|
*
|
||||||
|
* The maximum header table size.
|
||||||
|
*/
|
||||||
|
#define NGHTTP2_MAX_HEADER_TABLE_SIZE (1 << 16)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
*
|
*
|
||||||
|
@ -262,6 +269,11 @@ typedef enum {
|
||||||
* Callback was paused by the application
|
* Callback was paused by the application
|
||||||
*/
|
*/
|
||||||
NGHTTP2_ERR_PAUSE = -526,
|
NGHTTP2_ERR_PAUSE = -526,
|
||||||
|
/**
|
||||||
|
* There are too many in-flight SETTING frame and no more
|
||||||
|
* transmission of SETTINGS is allowed.
|
||||||
|
*/
|
||||||
|
NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527,
|
||||||
/**
|
/**
|
||||||
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
||||||
* under unexpected condition and cannot process any further data
|
* under unexpected condition and cannot process any further data
|
||||||
|
@ -379,9 +391,9 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
NGHTTP2_FLAG_END_PUSH_PROMISE = 0x4,
|
NGHTTP2_FLAG_END_PUSH_PROMISE = 0x4,
|
||||||
/**
|
/**
|
||||||
* The PONG flag.
|
* The ACK flag.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_FLAG_PONG = 0x1
|
NGHTTP2_FLAG_ACK = 0x1
|
||||||
} nghttp2_flag;
|
} nghttp2_flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -106,12 +106,11 @@ void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
void nghttp2_frame_settings_init(nghttp2_settings *frame,
|
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||||
nghttp2_settings_entry *iv, size_t niv)
|
nghttp2_settings_entry *iv, size_t niv)
|
||||||
{
|
{
|
||||||
memset(frame, 0, sizeof(nghttp2_settings));
|
memset(frame, 0, sizeof(nghttp2_settings));
|
||||||
nghttp2_frame_set_hd(&frame->hd, niv*8, NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE,
|
nghttp2_frame_set_hd(&frame->hd, niv*8, NGHTTP2_SETTINGS, flags, 0);
|
||||||
0);
|
|
||||||
frame->niv = niv;
|
frame->niv = niv;
|
||||||
frame->iv = iv;
|
frame->iv = iv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,7 +470,7 @@ void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame);
|
||||||
* ownership of |iv|, so caller must not free it. The |flags| are
|
* ownership of |iv|, so caller must not free it. The |flags| are
|
||||||
* bitwise-OR of one or more of nghttp2_settings_flag.
|
* bitwise-OR of one or more of nghttp2_settings_flag.
|
||||||
*/
|
*/
|
||||||
void nghttp2_frame_settings_init(nghttp2_settings *frame,
|
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||||
nghttp2_settings_entry *iv, size_t niv);
|
nghttp2_settings_entry *iv, size_t niv);
|
||||||
|
|
||||||
void nghttp2_frame_settings_free(nghttp2_settings *frame);
|
void nghttp2_frame_settings_free(nghttp2_settings *frame);
|
||||||
|
|
|
@ -191,6 +191,8 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
|
||||||
(*session_ptr)->goaway_flags = NGHTTP2_GOAWAY_NONE;
|
(*session_ptr)->goaway_flags = NGHTTP2_GOAWAY_NONE;
|
||||||
(*session_ptr)->last_stream_id = 0;
|
(*session_ptr)->last_stream_id = 0;
|
||||||
|
|
||||||
|
(*session_ptr)->inflight_niv = -1;
|
||||||
|
|
||||||
if(server) {
|
if(server) {
|
||||||
(*session_ptr)->server = 1;
|
(*session_ptr)->server = 1;
|
||||||
side_deflate = NGHTTP2_HD_SIDE_RESPONSE;
|
side_deflate = NGHTTP2_HD_SIDE_RESPONSE;
|
||||||
|
@ -341,6 +343,7 @@ void nghttp2_session_del(nghttp2_session *session)
|
||||||
if(session == NULL) {
|
if(session == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
free(session->inflight_iv);
|
||||||
nghttp2_inbound_frame_reset(session);
|
nghttp2_inbound_frame_reset(session);
|
||||||
nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL);
|
nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL);
|
||||||
nghttp2_session_ob_pq_free(&session->ob_pq);
|
nghttp2_session_ob_pq_free(&session->ob_pq);
|
||||||
|
@ -923,6 +926,27 @@ static int nghttp2_session_predicate_window_update_send
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function checks SETTINGS can be sent at this time.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS
|
||||||
|
* There is already another in-flight SETTINGS. Note that the
|
||||||
|
* current implementation only allows 1 in-flight SETTINGS frame
|
||||||
|
* without ACK flag set.
|
||||||
|
*/
|
||||||
|
static int nghttp2_session_predicate_settings_send(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame)
|
||||||
|
{
|
||||||
|
if((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 &&
|
||||||
|
session->inflight_niv != -1) {
|
||||||
|
return NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the maximum length of next data read. If the
|
* Returns the maximum length of next data read. If the
|
||||||
* connection-level and/or stream-wise flow control are enabled, the
|
* connection-level and/or stream-wise flow control are enabled, the
|
||||||
|
@ -1102,7 +1126,12 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
|
||||||
return framebuflen;
|
return framebuflen;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_SETTINGS:
|
case NGHTTP2_SETTINGS: {
|
||||||
|
int r;
|
||||||
|
r = nghttp2_session_predicate_settings_send(session, frame);
|
||||||
|
if(r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf,
|
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf,
|
||||||
&session->aob.framebufmax,
|
&session->aob.framebufmax,
|
||||||
&frame->settings);
|
&frame->settings);
|
||||||
|
@ -1110,6 +1139,7 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
|
||||||
return framebuflen;
|
return framebuflen;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NGHTTP2_PUSH_PROMISE: {
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
int r;
|
int r;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
@ -1412,9 +1442,29 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
|
||||||
}
|
}
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_SETTINGS:
|
case NGHTTP2_SETTINGS: {
|
||||||
/* nothing to do */
|
size_t i;
|
||||||
|
if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
/* Only update max concurrent stream here. Applying it without
|
||||||
|
ACK is safe because we can respond to the exceeding streams
|
||||||
|
with REFUSED_STREAM and client will retry later. */
|
||||||
|
for(i = frame->settings.niv; i > 0; --i) {
|
||||||
|
if(frame->settings.iv[i - 1].settings_id ==
|
||||||
|
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) {
|
||||||
|
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] =
|
||||||
|
frame->settings.iv[i - 1].value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(session->inflight_niv == -1);
|
||||||
|
session->inflight_iv = frame->settings.iv;
|
||||||
|
session->inflight_niv = frame->settings.niv;
|
||||||
|
frame->settings.iv = NULL;
|
||||||
|
frame->settings.niv = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case NGHTTP2_PUSH_PROMISE:
|
case NGHTTP2_PUSH_PROMISE:
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
|
@ -2187,6 +2237,10 @@ static int nghttp2_disable_remote_flow_control_func(nghttp2_map_entry *entry,
|
||||||
/*
|
/*
|
||||||
* Disable remote side connection-level flow control and stream-level
|
* Disable remote side connection-level flow control and stream-level
|
||||||
* flow control of existing streams.
|
* flow control of existing streams.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of negative error codes.
|
||||||
|
*
|
||||||
|
* The error code is always FATAL.
|
||||||
*/
|
*/
|
||||||
static int nghttp2_session_disable_remote_flow_control
|
static int nghttp2_session_disable_remote_flow_control
|
||||||
(nghttp2_session *session)
|
(nghttp2_session *session)
|
||||||
|
@ -2219,6 +2273,20 @@ static void nghttp2_session_disable_local_flow_control
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply SETTINGS values |iv| having |niv| elements to the local
|
||||||
|
* settings. SETTINGS_MAX_CONCURRENT_STREAMS is not applied here
|
||||||
|
* because it has been already applied on transmission of SETTINGS
|
||||||
|
* frame.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_HEADER_COMP
|
||||||
|
* The header table size is out of range
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory
|
||||||
|
*/
|
||||||
int nghttp2_session_update_local_settings(nghttp2_session *session,
|
int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||||
nghttp2_settings_entry *iv,
|
nghttp2_settings_entry *iv,
|
||||||
size_t niv)
|
size_t niv)
|
||||||
|
@ -2229,12 +2297,32 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||||
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS];
|
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS];
|
||||||
uint8_t new_flow_control = old_flow_control;
|
uint8_t new_flow_control = old_flow_control;
|
||||||
int32_t new_initial_window_size = -1;
|
int32_t new_initial_window_size = -1;
|
||||||
|
int32_t header_table_size = -1;
|
||||||
|
uint8_t header_table_size_seen = 0;
|
||||||
/* Use the value last seen. */
|
/* Use the value last seen. */
|
||||||
for(i = 0; i < niv; ++i) {
|
for(i = 0; i < niv; ++i) {
|
||||||
if(iv[i].settings_id == NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE) {
|
switch(iv[i].settings_id) {
|
||||||
|
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||||
|
header_table_size_seen = 1;
|
||||||
|
header_table_size = iv[i].value;
|
||||||
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
new_initial_window_size = iv[i].value;
|
new_initial_window_size = iv[i].value;
|
||||||
} else if(iv[i].settings_id == NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS) {
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS:
|
||||||
new_flow_control = iv[i].value;
|
new_flow_control = iv[i].value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(header_table_size_seen) {
|
||||||
|
if(header_table_size < 0 ||
|
||||||
|
header_table_size > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
|
||||||
|
return NGHTTP2_ERR_HEADER_COMP;
|
||||||
|
}
|
||||||
|
rv = nghttp2_hd_change_table_size(&session->hd_inflater,
|
||||||
|
header_table_size);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!old_flow_control && !new_flow_control && new_initial_window_size != -1) {
|
if(!old_flow_control && !new_flow_control && new_initial_window_size != -1) {
|
||||||
|
@ -2247,7 +2335,10 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i = 0; i < niv; ++i) {
|
for(i = 0; i < niv; ++i) {
|
||||||
if(iv[i].settings_id > 0 && iv[i].settings_id <= NGHTTP2_SETTINGS_MAX) {
|
/* SETTINGS_MAX_CONCURRENT_STREAMS has already been applied on
|
||||||
|
transmission of the SETTINGS frame. */
|
||||||
|
if(iv[i].settings_id > 0 && iv[i].settings_id <= NGHTTP2_SETTINGS_MAX &&
|
||||||
|
iv[i].settings_id != NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) {
|
||||||
session->local_settings[iv[i].settings_id] = iv[i].value;
|
session->local_settings[iv[i].settings_id] = iv[i].value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2259,7 +2350,8 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame)
|
nghttp2_frame *frame,
|
||||||
|
int noack)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2268,6 +2360,33 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
return nghttp2_session_handle_invalid_connection(session, frame,
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
|
if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
|
if(frame->settings.niv != 0) {
|
||||||
|
return nghttp2_session_handle_invalid_connection
|
||||||
|
(session, frame, NGHTTP2_FRAME_TOO_LARGE);
|
||||||
|
}
|
||||||
|
if(session->inflight_niv == -1) {
|
||||||
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
}
|
||||||
|
rv = nghttp2_session_update_local_settings(session, session->inflight_iv,
|
||||||
|
session->inflight_niv);
|
||||||
|
free(session->inflight_iv);
|
||||||
|
session->inflight_iv = NULL;
|
||||||
|
session->inflight_niv = -1;
|
||||||
|
if(rv != 0) {
|
||||||
|
nghttp2_error_code error_code = NGHTTP2_INTERNAL_ERROR;
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if(rv == NGHTTP2_ERR_HEADER_COMP) {
|
||||||
|
error_code = NGHTTP2_COMPRESSION_ERROR;
|
||||||
|
}
|
||||||
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
|
error_code);
|
||||||
|
}
|
||||||
|
return nghttp2_session_call_on_frame_received(session, frame);
|
||||||
|
}
|
||||||
/* Check ID/value pairs and persist them if necessary. */
|
/* Check ID/value pairs and persist them if necessary. */
|
||||||
memset(check, 0, sizeof(check));
|
memset(check, 0, sizeof(check));
|
||||||
for(i = (int)frame->settings.niv - 1; i >= 0; --i) {
|
for(i = (int)frame->settings.niv - 1; i >= 0; --i) {
|
||||||
|
@ -2282,6 +2401,21 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
check[entry->settings_id] = 1;
|
check[entry->settings_id] = 1;
|
||||||
switch(entry->settings_id) {
|
switch(entry->settings_id) {
|
||||||
|
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||||
|
if(entry->value > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
|
||||||
|
return nghttp2_session_handle_invalid_connection
|
||||||
|
(session, frame, NGHTTP2_COMPRESSION_ERROR);
|
||||||
|
}
|
||||||
|
rv = nghttp2_hd_change_table_size(&session->hd_deflater, entry->value);
|
||||||
|
if(rv != 0) {
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
} else {
|
||||||
|
return nghttp2_session_handle_invalid_connection
|
||||||
|
(session, frame, NGHTTP2_COMPRESSION_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
/* Update the initial window size of the all active streams */
|
/* Update the initial window size of the all active streams */
|
||||||
/* Check that initial_window_size < (1u << 31) */
|
/* Check that initial_window_size < (1u << 31) */
|
||||||
|
@ -2306,6 +2440,8 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
if(session->remote_settings[entry->settings_id] == 0) {
|
if(session->remote_settings[entry->settings_id] == 0) {
|
||||||
rv = nghttp2_session_disable_remote_flow_control(session);
|
rv = nghttp2_session_disable_remote_flow_control(session);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
|
/* FATAL */
|
||||||
|
assert(rv < NGHTTP2_ERR_FATAL);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2319,6 +2455,16 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
session->remote_settings[entry->settings_id] = entry->value;
|
session->remote_settings[entry->settings_id] = entry->value;
|
||||||
}
|
}
|
||||||
|
if(!noack) {
|
||||||
|
rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||||
|
if(rv != 0) {
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return nghttp2_session_handle_invalid_connection
|
||||||
|
(session, frame, NGHTTP2_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
return nghttp2_session_call_on_frame_received(session, frame);
|
return nghttp2_session_call_on_frame_received(session, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2401,9 +2547,9 @@ int nghttp2_session_on_ping_received(nghttp2_session *session,
|
||||||
return nghttp2_session_handle_invalid_connection(session, frame,
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
if((frame->hd.flags & NGHTTP2_FLAG_PONG) == 0) {
|
if((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
|
||||||
/* Peer sent ping, so ping it back */
|
/* Peer sent ping, so ping it back */
|
||||||
r = nghttp2_session_add_ping(session, NGHTTP2_FLAG_PONG,
|
r = nghttp2_session_add_ping(session, NGHTTP2_FLAG_ACK,
|
||||||
frame->ping.opaque_data);
|
frame->ping.opaque_data);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
return r;
|
return r;
|
||||||
|
@ -2645,7 +2791,7 @@ static int nghttp2_session_process_ctrl_frame(nghttp2_session *session)
|
||||||
session->iframe.buf,
|
session->iframe.buf,
|
||||||
session->iframe.buflen);
|
session->iframe.buflen);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
r = nghttp2_session_on_settings_received(session, frame);
|
r = nghttp2_session_on_settings_received(session, frame, 0 /* ACK */);
|
||||||
if(r != NGHTTP2_ERR_PAUSE) {
|
if(r != NGHTTP2_ERR_PAUSE) {
|
||||||
nghttp2_frame_settings_free(&frame->settings);
|
nghttp2_frame_settings_free(&frame->settings);
|
||||||
}
|
}
|
||||||
|
@ -3328,6 +3474,37 @@ int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
||||||
|
const nghttp2_settings_entry *iv, size_t niv)
|
||||||
|
{
|
||||||
|
nghttp2_frame *frame;
|
||||||
|
nghttp2_settings_entry *iv_copy;
|
||||||
|
int r;
|
||||||
|
if(!nghttp2_iv_check(iv, niv,
|
||||||
|
session->local_settings
|
||||||
|
[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS])) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
frame = malloc(sizeof(nghttp2_frame));
|
||||||
|
if(frame == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
iv_copy = nghttp2_frame_iv_copy(iv, niv);
|
||||||
|
if(iv_copy == NULL) {
|
||||||
|
free(frame);
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
nghttp2_frame_settings_init(&frame->settings, flags, iv_copy, niv);
|
||||||
|
r = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
||||||
|
if(r != 0) {
|
||||||
|
/* The only expected error is fatal one */
|
||||||
|
assert(r < NGHTTP2_ERR_FATAL);
|
||||||
|
nghttp2_frame_settings_free(&frame->settings);
|
||||||
|
free(frame);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
|
ssize_t nghttp2_session_pack_data(nghttp2_session *session,
|
||||||
uint8_t **buf_ptr, size_t *buflen_ptr,
|
uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
size_t datamax,
|
size_t datamax,
|
||||||
|
@ -3481,7 +3658,7 @@ int nghttp2_session_upgrade(nghttp2_session *session,
|
||||||
memset(&frame.hd, 0, sizeof(frame.hd));
|
memset(&frame.hd, 0, sizeof(frame.hd));
|
||||||
frame.settings.iv = iv;
|
frame.settings.iv = iv;
|
||||||
frame.settings.niv = niv;
|
frame.settings.niv = niv;
|
||||||
rv = nghttp2_session_on_settings_received(session, &frame);
|
rv = nghttp2_session_on_settings_received(session, &frame, 1 /* No ACK */);
|
||||||
} else {
|
} else {
|
||||||
rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,6 +188,13 @@ struct nghttp2_session {
|
||||||
/* Settings value of the local endpoint. */
|
/* Settings value of the local endpoint. */
|
||||||
uint32_t local_settings[NGHTTP2_SETTINGS_MAX+1];
|
uint32_t local_settings[NGHTTP2_SETTINGS_MAX+1];
|
||||||
|
|
||||||
|
/* In-flight SETTINGS values. NULL does not necessarily mean there
|
||||||
|
is no in-flight SETTINGS. */
|
||||||
|
nghttp2_settings_entry *inflight_iv;
|
||||||
|
/* The number of entries in |inflight_iv|. -1 if there is no
|
||||||
|
in-flight SETTINGS. */
|
||||||
|
ssize_t inflight_niv;
|
||||||
|
|
||||||
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
|
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
|
||||||
uint32_t opt_flags;
|
uint32_t opt_flags;
|
||||||
|
|
||||||
|
@ -295,6 +302,18 @@ int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
int32_t window_size_increment);
|
int32_t window_size_increment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds SETTINGS frame.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
||||||
|
const nghttp2_settings_entry *iv, size_t niv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates new stream in |session| with stream ID |stream_id|,
|
* Creates new stream in |session| with stream ID |stream_id|,
|
||||||
* priority |pri| and flags |flags|. NGHTTP2_FLAG_END_STREAM flag is
|
* priority |pri| and flags |flags|. NGHTTP2_FLAG_END_STREAM flag is
|
||||||
|
@ -386,19 +405,33 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
|
||||||
* Called when RST_STREAM is received, assuming |frame| is properly
|
* Called when RST_STREAM is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
*
|
*
|
||||||
* This function returns 0 and never fail.
|
* This function returns 0 if it succeeds, or one the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* TBD
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when SETTINGS is received, assuming |frame| is properly
|
* Called when SETTINGS is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized. If |noack| is non-zero, SETTINGS with ACK will not be
|
||||||
|
* submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
|
||||||
|
* with ACK will not be submitted regardless of |noack|.
|
||||||
*
|
*
|
||||||
* This function returns 0 and never fail.
|
* This function returns 0 if it succeeds, or one the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory
|
||||||
|
* NGHTTP2_ERR_PAUSE
|
||||||
|
* Callback function returns NGHTTP2_ERR_PAUSE
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame,
|
||||||
|
int noack);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when PUSH_PROMISE is received, assuming |frame| is properly
|
* Called when PUSH_PROMISE is received, assuming |frame| is properly
|
||||||
|
|
|
@ -209,39 +209,7 @@ int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||||
const nghttp2_settings_entry *iv, size_t niv)
|
const nghttp2_settings_entry *iv, size_t niv)
|
||||||
{
|
{
|
||||||
nghttp2_frame *frame;
|
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
||||||
nghttp2_settings_entry *iv_copy;
|
|
||||||
int r;
|
|
||||||
if(!nghttp2_iv_check(iv, niv,
|
|
||||||
session->local_settings
|
|
||||||
[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS])) {
|
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
frame = malloc(sizeof(nghttp2_frame));
|
|
||||||
if(frame == NULL) {
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
iv_copy = nghttp2_frame_iv_copy(iv, niv);
|
|
||||||
if(iv_copy == NULL) {
|
|
||||||
free(frame);
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
nghttp2_frame_settings_init(&frame->settings, iv_copy, niv);
|
|
||||||
|
|
||||||
r = nghttp2_session_update_local_settings(session, iv_copy, niv);
|
|
||||||
if(r != 0) {
|
|
||||||
nghttp2_frame_settings_free(&frame->settings);
|
|
||||||
free(frame);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
|
||||||
if(r != 0) {
|
|
||||||
/* The only expected error is fatal one */
|
|
||||||
assert(r < NGHTTP2_ERR_FATAL);
|
|
||||||
nghttp2_frame_settings_free(&frame->settings);
|
|
||||||
free(frame);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||||
|
|
|
@ -80,12 +80,16 @@ namespace {
|
||||||
const char* strsettingsid(int32_t id)
|
const char* strsettingsid(int32_t id)
|
||||||
{
|
{
|
||||||
switch(id) {
|
switch(id) {
|
||||||
|
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||||
|
return "SETTINGS_HEADER_TABLE_SIZE";
|
||||||
|
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
||||||
|
return "SETTINGS_ENABLE_PUSH";
|
||||||
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
||||||
return "MAX_CONCURRENT_STREAMS";
|
return "SETTINGS_MAX_CONCURRENT_STREAMS";
|
||||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
return "INITIAL_WINDOW_SIZE";
|
return "SETTINGS_INITIAL_WINDOW_SIZE";
|
||||||
case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS:
|
case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS:
|
||||||
return "FLOW_CONTROL_OPTIONS";
|
return "SETTINGS_FLOW_CONTROL_OPTIONS";
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -208,14 +212,19 @@ void print_flags(const nghttp2_frame_hd& hd)
|
||||||
s += "PRIORITY";
|
s += "PRIORITY";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_SETTINGS:
|
||||||
|
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
|
s += "ACK";
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NGHTTP2_PUSH_PROMISE:
|
case NGHTTP2_PUSH_PROMISE:
|
||||||
if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) {
|
if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) {
|
||||||
s += "END_PUSH_PROMISE";
|
s += "END_PUSH_PROMISE";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_PING:
|
case NGHTTP2_PING:
|
||||||
if(hd.flags & NGHTTP2_FLAG_PONG) {
|
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
s += "PONG";
|
s += "ACK";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,7 +223,8 @@ void test_nghttp2_frame_pack_settings()
|
||||||
iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS;
|
||||||
iv[2].value = 1;
|
iv[2].value = 1;
|
||||||
|
|
||||||
nghttp2_frame_settings_init(&frame, nghttp2_frame_iv_copy(iv, 3), 3);
|
nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE,
|
||||||
|
nghttp2_frame_iv_copy(iv, 3), 3);
|
||||||
framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame);
|
framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame);
|
||||||
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH+3*8 == framelen);
|
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH+3*8 == framelen);
|
||||||
|
|
||||||
|
@ -290,14 +291,14 @@ void test_nghttp2_frame_pack_ping(void)
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
ssize_t framelen;
|
ssize_t framelen;
|
||||||
const uint8_t opaque_data[] = "01234567";
|
const uint8_t opaque_data[] = "01234567";
|
||||||
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_PONG, opaque_data);
|
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data);
|
||||||
framelen = nghttp2_frame_pack_ping(&buf, &buflen, &frame);
|
framelen = nghttp2_frame_pack_ping(&buf, &buflen, &frame);
|
||||||
CU_ASSERT(0 == nghttp2_frame_unpack_ping
|
CU_ASSERT(0 == nghttp2_frame_unpack_ping
|
||||||
(&oframe,
|
(&oframe,
|
||||||
&buf[0], NGHTTP2_FRAME_HEAD_LENGTH,
|
&buf[0], NGHTTP2_FRAME_HEAD_LENGTH,
|
||||||
&buf[NGHTTP2_FRAME_HEAD_LENGTH],
|
&buf[NGHTTP2_FRAME_HEAD_LENGTH],
|
||||||
framelen - NGHTTP2_FRAME_HEAD_LENGTH));
|
framelen - NGHTTP2_FRAME_HEAD_LENGTH));
|
||||||
check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_PONG, 0, &oframe.hd);
|
check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_ACK, 0, &oframe.hd);
|
||||||
CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, sizeof(opaque_data) - 1)
|
CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, sizeof(opaque_data) - 1)
|
||||||
== 0);
|
== 0);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
|
@ -1134,6 +1134,7 @@ void test_nghttp2_session_on_settings_received(void)
|
||||||
nghttp2_frame frame;
|
nghttp2_frame frame;
|
||||||
const size_t niv = 5;
|
const size_t niv = 5;
|
||||||
nghttp2_settings_entry iv[255];
|
nghttp2_settings_entry iv[255];
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
iv[0].value = 50;
|
iv[0].value = 50;
|
||||||
|
@ -1166,9 +1167,10 @@ void test_nghttp2_session_on_settings_received(void)
|
||||||
stream1->remote_window_size = 16*1024;
|
stream1->remote_window_size = 16*1024;
|
||||||
stream2->remote_window_size = -48*1024;
|
stream2->remote_window_size = -48*1024;
|
||||||
|
|
||||||
nghttp2_frame_settings_init(&frame.settings, dup_iv(iv, niv), niv);
|
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
|
||||||
|
dup_iv(iv, niv), niv);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||||
CU_ASSERT(1000000009 ==
|
CU_ASSERT(1000000009 ==
|
||||||
session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
||||||
CU_ASSERT(64*1024 ==
|
CU_ASSERT(64*1024 ==
|
||||||
|
@ -1181,7 +1183,7 @@ void test_nghttp2_session_on_settings_received(void)
|
||||||
|
|
||||||
frame.settings.iv[2].value = 16*1024;
|
frame.settings.iv[2].value = 16*1024;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||||
|
|
||||||
CU_ASSERT(16*1024 == stream1->remote_window_size);
|
CU_ASSERT(16*1024 == stream1->remote_window_size);
|
||||||
CU_ASSERT(-48*1024 == stream2->remote_window_size);
|
CU_ASSERT(-48*1024 == stream2->remote_window_size);
|
||||||
|
@ -1193,6 +1195,37 @@ void test_nghttp2_session_on_settings_received(void)
|
||||||
nghttp2_frame_settings_free(&frame.settings);
|
nghttp2_frame_settings_free(&frame.settings);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
/* Check ACK with niv > 0 */
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_ACK,
|
||||||
|
dup_iv(iv, 1), 1);
|
||||||
|
/* Specify inflight_iv deliberately */
|
||||||
|
session->inflight_iv = frame.settings.iv;
|
||||||
|
session->inflight_niv = frame.settings.niv;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
CU_ASSERT(item != NULL);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
session->inflight_iv = NULL;
|
||||||
|
session->inflight_niv = -1;
|
||||||
|
|
||||||
|
nghttp2_frame_settings_free(&frame.settings);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
/* Check ACK against no inflight SETTINGS */
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
CU_ASSERT(item != NULL);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
nghttp2_frame_settings_free(&frame.settings);
|
||||||
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_on_push_promise_received(void)
|
void test_nghttp2_session_on_push_promise_received(void)
|
||||||
|
@ -1346,7 +1379,7 @@ void test_nghttp2_session_on_ping_received(void)
|
||||||
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||||
|
|
||||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_PONG, opaque_data);
|
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_ACK, opaque_data);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_on_ping_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_ping_received(session, &frame));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||||
|
@ -1362,7 +1395,7 @@ void test_nghttp2_session_on_ping_received(void)
|
||||||
CU_ASSERT(2 == user_data.frame_recv_cb_called);
|
CU_ASSERT(2 == user_data.frame_recv_cb_called);
|
||||||
top = nghttp2_session_get_ob_pq_top(session);
|
top = nghttp2_session_get_ob_pq_top(session);
|
||||||
CU_ASSERT(NGHTTP2_PING == OB_CTRL_TYPE(top));
|
CU_ASSERT(NGHTTP2_PING == OB_CTRL_TYPE(top));
|
||||||
CU_ASSERT(NGHTTP2_FLAG_PONG == OB_CTRL(top)->hd.flags);
|
CU_ASSERT(NGHTTP2_FLAG_ACK == OB_CTRL(top)->hd.flags);
|
||||||
CU_ASSERT(memcmp(opaque_data, OB_CTRL(top)->ping.opaque_data, 8) == 0);
|
CU_ASSERT(memcmp(opaque_data, OB_CTRL(top)->ping.opaque_data, 8) == 0);
|
||||||
|
|
||||||
nghttp2_frame_ping_free(&frame.ping);
|
nghttp2_frame_ping_free(&frame.ping);
|
||||||
|
@ -2260,6 +2293,7 @@ void test_nghttp2_submit_settings(void)
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
nghttp2_frame *frame;
|
nghttp2_frame *frame;
|
||||||
nghttp2_settings_entry iv[5];
|
nghttp2_settings_entry iv[5];
|
||||||
|
nghttp2_frame ack_frame;
|
||||||
|
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
iv[0].value = 5;
|
iv[0].value = 5;
|
||||||
|
@ -2296,15 +2330,6 @@ void test_nghttp2_submit_settings(void)
|
||||||
/* Now sends without 5th one */
|
/* Now sends without 5th one */
|
||||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 4));
|
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 4));
|
||||||
|
|
||||||
/* Make sure that local settings are changed */
|
|
||||||
CU_ASSERT(50 ==
|
|
||||||
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
|
||||||
CU_ASSERT(16*1024 ==
|
|
||||||
session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
|
|
||||||
CU_ASSERT(1 ==
|
|
||||||
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]);
|
|
||||||
CU_ASSERT(0 == session->local_flow_control);
|
|
||||||
|
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
CU_ASSERT(NGHTTP2_SETTINGS == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_SETTINGS == OB_CTRL_TYPE(item));
|
||||||
|
@ -2323,6 +2348,20 @@ void test_nghttp2_submit_settings(void)
|
||||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
CU_ASSERT(1 == ud.frame_send_cb_called);
|
CU_ASSERT(1 == ud.frame_send_cb_called);
|
||||||
|
|
||||||
|
/* Only SETTINGS_MAX_CONCURRENT_STREAMS is applied on transmission */
|
||||||
|
CU_ASSERT(50 ==
|
||||||
|
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
||||||
|
|
||||||
|
nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||||
|
nghttp2_frame_settings_free(&ack_frame.settings);
|
||||||
|
|
||||||
|
CU_ASSERT(16*1024 ==
|
||||||
|
session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
|
||||||
|
CU_ASSERT(1 ==
|
||||||
|
session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]);
|
||||||
|
CU_ASSERT(0 == session->local_flow_control);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2333,7 +2372,9 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
nghttp2_settings_entry iv[4];
|
nghttp2_settings_entry iv[4];
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
my_user_data ud;
|
nghttp2_frame ack_frame;
|
||||||
|
|
||||||
|
nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||||
|
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||||
iv[0].value = 16*1024;
|
iv[0].value = 16*1024;
|
||||||
|
@ -2342,9 +2383,9 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
||||||
iv[1].value = 1;
|
iv[1].value = 1;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.send_callback = block_count_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
|
|
||||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
||||||
NGHTTP2_PRI_DEFAULT,
|
NGHTTP2_PRI_DEFAULT,
|
||||||
|
@ -2358,6 +2399,8 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
||||||
stream->local_flow_control = 0;
|
stream->local_flow_control = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, 1);
|
stream = nghttp2_session_get_stream(session, 1);
|
||||||
CU_ASSERT(0 == stream->recv_window_size);
|
CU_ASSERT(0 == stream->recv_window_size);
|
||||||
|
@ -2366,9 +2409,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
||||||
stream = nghttp2_session_get_stream(session, 3);
|
stream = nghttp2_session_get_stream(session, 3);
|
||||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
||||||
|
|
||||||
/* Setting block_count = 0 will pop first entry SETTINGS */
|
|
||||||
ud.block_count = 0;
|
|
||||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_WINDOW_UPDATE == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_WINDOW_UPDATE == OB_CTRL_TYPE(item));
|
||||||
CU_ASSERT(32768 == OB_CTRL(item)->window_update.window_size_increment);
|
CU_ASSERT(32768 == OB_CTRL(item)->window_update.window_size_increment);
|
||||||
|
@ -2376,28 +2416,35 @@ void test_nghttp2_submit_settings_update_local_window_size(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
/* Check flow control disabled case */
|
/* Check flow control disabled case */
|
||||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
||||||
NGHTTP2_PRI_DEFAULT,
|
NGHTTP2_PRI_DEFAULT,
|
||||||
NGHTTP2_STREAM_OPENED, NULL);
|
NGHTTP2_STREAM_OPENED, NULL);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2));
|
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||||
|
|
||||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
/* Check overflow case */
|
/* Check overflow case */
|
||||||
iv[0].value = 128*1024;
|
iv[0].value = 128*1024;
|
||||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
|
||||||
NGHTTP2_PRI_DEFAULT,
|
NGHTTP2_PRI_DEFAULT,
|
||||||
NGHTTP2_STREAM_OPENED, NULL);
|
NGHTTP2_STREAM_OPENED, NULL);
|
||||||
stream->local_window_size = NGHTTP2_MAX_WINDOW_SIZE;
|
stream->local_window_size = NGHTTP2_MAX_WINDOW_SIZE;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||||
|
|
||||||
CU_ASSERT(NGHTTP2_STREAM_CLOSING == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_CLOSING == stream->state);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
nghttp2_frame_settings_free(&ack_frame.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_nghttp2_submit_push_promise(void)
|
void test_nghttp2_submit_push_promise(void)
|
||||||
|
@ -3068,8 +3115,9 @@ void test_nghttp2_session_flow_control(void)
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||||
iv[0].value = 32*1024;
|
iv[0].value = 32*1024;
|
||||||
|
|
||||||
nghttp2_frame_settings_init(&settings_frame.settings, dup_iv(iv, 1), 1);
|
nghttp2_frame_settings_init(&settings_frame.settings, NGHTTP2_FLAG_NONE,
|
||||||
nghttp2_session_on_settings_received(session, &settings_frame);
|
dup_iv(iv, 1), 1);
|
||||||
|
nghttp2_session_on_settings_received(session, &settings_frame, 1);
|
||||||
nghttp2_frame_settings_free(&settings_frame.settings);
|
nghttp2_frame_settings_free(&settings_frame.settings);
|
||||||
|
|
||||||
/* Sends another 8KiB data */
|
/* Sends another 8KiB data */
|
||||||
|
@ -3119,8 +3167,9 @@ void test_nghttp2_session_flow_control_disable_remote(void)
|
||||||
CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length);
|
CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length);
|
||||||
|
|
||||||
/* Disable flow control entirely */
|
/* Disable flow control entirely */
|
||||||
nghttp2_frame_settings_init(&frame.settings, dup_iv(&iv, 1), 1);
|
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
|
||||||
nghttp2_session_on_settings_received(session, &frame);
|
dup_iv(&iv, 1), 1);
|
||||||
|
nghttp2_session_on_settings_received(session, &frame, 1);
|
||||||
|
|
||||||
/* Check both connection and stream-level remote_flow_control is
|
/* Check both connection and stream-level remote_flow_control is
|
||||||
disabled */
|
disabled */
|
||||||
|
@ -3141,7 +3190,9 @@ void test_nghttp2_session_flow_control_disable_local(void)
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
nghttp2_settings_entry iv[1];
|
nghttp2_settings_entry iv[1];
|
||||||
|
nghttp2_frame ack_frame;
|
||||||
|
|
||||||
|
nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
|
|
||||||
|
@ -3155,11 +3206,15 @@ void test_nghttp2_session_flow_control_disable_local(void)
|
||||||
iv[0].value = 1;
|
iv[0].value = 1;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv,
|
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv,
|
||||||
sizeof(iv)/sizeof(iv[0])));
|
ARRLEN(iv)));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
|
||||||
|
|
||||||
CU_ASSERT(0 == stream->local_flow_control);
|
CU_ASSERT(0 == stream->local_flow_control);
|
||||||
CU_ASSERT(0 == session->local_flow_control);
|
CU_ASSERT(0 == session->local_flow_control);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
nghttp2_frame_settings_free(&ack_frame.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_flow_control_data_recv(void)
|
void test_nghttp2_session_flow_control_data_recv(void)
|
||||||
|
|
Loading…
Reference in New Issue