Implement SETTINGS_ENABLE_PUSH

It is not clear that SETTINGS_ENABLE_PUSH = 0 disallows HEADERS
to the reserved streams. For now, we just check the reception
and transmission of PUSH_PROMISE against SETTINGS_ENABLE_PUSH.
This commit is contained in:
Tatsuhiro Tsujikawa 2013-11-02 16:53:06 +09:00
parent 29ef3fde8b
commit 4bc44b0c0b
3 changed files with 63 additions and 2 deletions

View File

@ -274,6 +274,10 @@ typedef enum {
* transmission of SETTINGS is allowed. * transmission of SETTINGS is allowed.
*/ */
NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527, NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527,
/**
* The server push is disabled.
*/
NGHTTP2_ERR_PUSH_DISABLED = -528,
/** /**
* 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

View File

@ -865,6 +865,8 @@ static int nghttp2_session_predicate_priority_send
* NGHTTP2_ERR_STREAM_SHUT_WR * NGHTTP2_ERR_STREAM_SHUT_WR
* The transmission is not allowed for this stream (e.g., a frame * The transmission is not allowed for this stream (e.g., a frame
* with END_STREAM flag set has already sent) * with END_STREAM flag set has already sent)
* NGHTTP2_ERR_PUSH_DISABLED
* The remote peer disabled reception of PUSH_PROMISE.
*/ */
static int nghttp2_session_predicate_push_promise_send static int nghttp2_session_predicate_push_promise_send
(nghttp2_session *session, int32_t stream_id) (nghttp2_session *session, int32_t stream_id)
@ -881,6 +883,9 @@ static int nghttp2_session_predicate_push_promise_send
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
if(session->remote_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) {
return NGHTTP2_ERR_PUSH_DISABLED;
}
if(stream->state == NGHTTP2_STREAM_CLOSING) { if(stream->state == NGHTTP2_STREAM_CLOSING) {
return NGHTTP2_ERR_STREAM_CLOSING; return NGHTTP2_ERR_STREAM_CLOSING;
} }
@ -2488,6 +2493,10 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
return nghttp2_session_handle_invalid_connection(session, frame, return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_INTERNAL_ERROR); NGHTTP2_INTERNAL_ERROR);
} }
if(session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) {
return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR);
}
if(session->goaway_flags) { if(session->goaway_flags) {
/* We just dicard PUSH_PROMISE after GOAWAY is sent or /* We just dicard PUSH_PROMISE after GOAWAY is sent or
received. */ received. */

View File

@ -1304,6 +1304,28 @@ void test_nghttp2_session_on_push_promise_received(void)
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
nghttp2_session_del(session); nghttp2_session_del(session);
/* Disable PUSH */
nghttp2_session_client_new(&session, &callbacks, &user_data);
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL);
session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] = 0;
nvlen = nghttp2_nv_array_from_cstr(&nva, nv);
nghttp2_frame_push_promise_init(&frame.push_promise,
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, 2,
nva, nvlen);
user_data.frame_recv_cb_called = 0;
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
nghttp2_session_del(session);
} }
void test_nghttp2_session_on_ping_received(void) void test_nghttp2_session_on_ping_received(void)
@ -1637,11 +1659,14 @@ void test_nghttp2_session_send_push_promise(void)
nghttp2_stream *stream; nghttp2_stream *stream;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
nghttp2_settings_entry iv;
my_user_data ud;
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;
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE, nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
NULL); NULL);
@ -1655,10 +1680,33 @@ void test_nghttp2_session_send_push_promise(void)
stream = nghttp2_session_get_stream(session, 2); stream = nghttp2_session_get_stream(session, 2);
CU_ASSERT(NGHTTP2_STREAM_RESERVED == stream->state); CU_ASSERT(NGHTTP2_STREAM_RESERVED == stream->state);
/* Received ENABLE_PUSH = 0 */
iv.settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
iv.value = 0;
frame = malloc(sizeof(nghttp2_frame));
nghttp2_frame_settings_init(&frame->settings, NGHTTP2_FLAG_NONE,
dup_iv(&iv, 1), 1);
nghttp2_session_on_settings_received(session, frame, 1);
nghttp2_frame_settings_free(&frame->settings);
free(frame);
frame = malloc(sizeof(nghttp2_frame));
nvlen = nghttp2_nv_array_from_cstr(&nva, nv);
nghttp2_frame_push_promise_init(&frame->push_promise,
NGHTTP2_FLAG_END_PUSH_PROMISE, 1, -1,
nva, nvlen);
nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
ud.frame_not_send_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(1 == ud.frame_not_send_cb_called);
CU_ASSERT(NGHTTP2_PUSH_PROMISE == ud.not_sent_frame_type);
CU_ASSERT(NGHTTP2_ERR_PUSH_DISABLED == ud.not_sent_error);
nghttp2_session_del(session); nghttp2_session_del(session);
/* PUSH_PROMISE from client is error */ /* PUSH_PROMISE from client is error */
nghttp2_session_client_new(&session, &callbacks, NULL); nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE, nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
NULL); NULL);