Add nghttp2_option_set_no_auto_ping_ack() option

This option prevents the nghttp2 library from sending PING frame with
ACK flag set in the reply to incoming PING frame.  To allow the
application to send PING with ACK flag set, nghttp2_submit_ping() now
recognizes NGHTTP2_FLAG_PING in its flags parameter.
This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-29 23:39:50 +09:00
parent a21c87d11c
commit e453759637
8 changed files with 70 additions and 6 deletions

View File

@ -55,6 +55,7 @@ APIDOCS= \
nghttp2_option_del.rst \
nghttp2_option_new.rst \
nghttp2_option_set_max_reserved_remote_streams.rst \
nghttp2_option_set_no_auto_ping_ack.rst \
nghttp2_option_set_no_auto_window_update.rst \
nghttp2_option_set_no_http_messaging.rst \
nghttp2_option_set_no_recv_client_magic.rst \

View File

@ -2251,6 +2251,20 @@ NGHTTP2_EXTERN void
nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
uint8_t type);
/**
* @function
*
* This option prevents the library from sending PING frame with ACK
* flag set automatically when PING frame without ACK flag set is
* received. If this option is set to nonzero, the library won't send
* PING frame with ACK flag set in the response for incoming PING
* frame. The application can send PING frame with ACK flag set using
* `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
* parameter.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
int val);
/**
* @function
*
@ -3783,8 +3797,12 @@ nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
* received PING frame. The library automatically submits PING frame
* in this case.
*
* The |flags| is currently ignored and should be
* :enum:`NGHTTP2_FLAG_NONE`.
* The |flags| is bitwise OR of 0 or more of the following value.
*
* * :enum:`NGHTTP2_FLAG_ACK`
*
* Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
* should be :enum:`NGHTTP2_FLAG_NONE`.
*
* If the |opaque_data| is non ``NULL``, then it should point to the 8
* bytes array of memory to specify opaque data to send with PING

View File

@ -73,3 +73,8 @@ void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
option->user_recv_ext_types[type / 8] =
(uint8_t)(option->user_recv_ext_types[type / 8] | (1 << (type & 0x7)));
}
void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) {
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK;
option->no_auto_ping_ack = val;
}

View File

@ -60,7 +60,8 @@ typedef enum {
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6
} nghttp2_option_flag;
/**
@ -92,6 +93,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_NO_HTTP_MESSAGING
*/
int no_http_messaging;
/**
* NGHTTP2_OPT_NO_AUTO_PING_ACK
*/
int no_auto_ping_ack;
/**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/

View File

@ -416,6 +416,11 @@ static int session_new(nghttp2_session **session_ptr,
memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types,
sizeof((*session_ptr)->user_recv_ext_types));
}
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_PING_ACK) &&
option->no_auto_ping_ack) {
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_PING_ACK;
}
}
(*session_ptr)->callbacks = *callbacks;
@ -4364,7 +4369,8 @@ int nghttp2_session_on_ping_received(nghttp2_session *session,
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PING: stream_id != 0");
}
if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 &&
if ((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK) == 0 &&
(frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 &&
!session_is_closing(session)) {
/* Peer sent ping, so ping it back */
rv = nghttp2_session_add_ping(session, NGHTTP2_FLAG_ACK,

View File

@ -50,7 +50,8 @@ extern int nghttp2_enable_strict_preface;
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3
} nghttp2_optmask;
typedef enum {

View File

@ -211,8 +211,9 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
nvlen, NULL, stream_user_data);
}
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags _U_,
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
const uint8_t *opaque_data) {
flags &= NGHTTP2_FLAG_ACK;
return nghttp2_session_add_ping(session, NGHTTP2_FLAG_NONE, opaque_data);
}

View File

@ -3095,6 +3095,7 @@ void test_nghttp2_session_on_ping_received(void) {
nghttp2_frame frame;
nghttp2_outbound_item *top;
const uint8_t opaque_data[] = "01234567";
nghttp2_option *option;
user_data.frame_recv_cb_called = 0;
user_data.invalid_frame_recv_cb_called = 0;
@ -3125,6 +3126,23 @@ void test_nghttp2_session_on_ping_received(void) {
nghttp2_frame_ping_free(&frame.ping);
nghttp2_session_del(session);
/* Use nghttp2_option_set_no_auto_ping_ack() */
nghttp2_option_new(&option);
nghttp2_option_set_no_auto_ping_ack(option, 1);
nghttp2_session_server_new2(&session, &callbacks, &user_data, option);
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_ping_received(session, &frame));
CU_ASSERT(1 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_outbound_queue_top(&session->ob_urgent));
nghttp2_frame_ping_free(&frame.ping);
nghttp2_session_del(session);
nghttp2_option_del(option);
}
void test_nghttp2_session_on_goaway_received(void) {
@ -6153,6 +6171,15 @@ void test_nghttp2_session_set_option(void) {
CU_ASSERT(99 == session->max_incoming_reserved_streams);
nghttp2_session_del(session);
/* Test for nghttp2_option_set_no_auto_ping_ack */
nghttp2_option_set_no_auto_ping_ack(option, 1);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK);
nghttp2_session_del(session);
nghttp2_option_del(option);
}