diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index a43aca59..6c06fdd3 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -307,6 +307,10 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob) aob->state = NGHTTP2_OB_POP_ITEM; } +/* This global variable exists for tests where we want to disable this + check. */ +int nghttp2_enable_strict_first_settings_check = 1; + static int session_new(nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, void *user_data, @@ -422,6 +426,10 @@ static int session_new(nghttp2_session **session_ptr, iframe->state = NGHTTP2_IB_READ_CLIENT_PREFACE; iframe->payloadleft = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN; + } else if(nghttp2_enable_strict_first_settings_check) { + nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; + + iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; } return 0; @@ -4390,9 +4398,38 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(iframe->payloadleft == 0) { session_inbound_frame_reset(session); + iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; } break; + case NGHTTP2_IB_READ_FIRST_SETTINGS: + DEBUGF(fprintf(stderr, "recv: [IB_READ_FIRST_SETTINGS]\n")); + + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + + if(nghttp2_buf_mark_avail(&iframe->sbuf)) { + return in - first; + } + + if(iframe->sbuf.pos[3] != NGHTTP2_SETTINGS) { + busy = 1; + + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + rv = nghttp2_session_terminate_session_with_reason + (session, NGHTTP2_PROTOCOL_ERROR, "SETTINGS expected"); + + if(nghttp2_is_fatal(rv)) { + return rv; + } + + break; + } + + iframe->state = NGHTTP2_IB_READ_HEAD; + + /* Fall through */ case NGHTTP2_IB_READ_HEAD: { int on_begin_frame_called = 0; diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 4b5d94ec..34a095f9 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -67,6 +67,7 @@ typedef struct { typedef enum { /* Receiving frame header */ NGHTTP2_IB_READ_CLIENT_PREFACE, + NGHTTP2_IB_READ_FIRST_SETTINGS, NGHTTP2_IB_READ_HEAD, NGHTTP2_IB_READ_NBYTE, NGHTTP2_IB_READ_HEADER_BLOCK, diff --git a/tests/main.c b/tests/main.c index 126b9d39..6981124c 100644 --- a/tests/main.c +++ b/tests/main.c @@ -41,6 +41,8 @@ #include "nghttp2_helper_test.h" #include "nghttp2_buf_test.h" +extern int nghttp2_enable_strict_first_settings_check; + static int init_suite1(void) { return 0; @@ -57,6 +59,8 @@ int main(int argc, char* argv[]) CU_pSuite pSuite = NULL; unsigned int num_tests_failed; + nghttp2_enable_strict_first_settings_check = 0; + /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index ce30d549..19598226 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -6494,7 +6494,7 @@ void test_nghttp2_session_recv_client_preface(void) NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN); - CU_ASSERT(NGHTTP2_IB_READ_HEAD == session->iframe.state); + CU_ASSERT(NGHTTP2_IB_READ_FIRST_SETTINGS == session->iframe.state); nghttp2_session_del(session);