From 4d93dd9d9176d03c07ee57aa5cf03983f311bee2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 28 Oct 2014 23:35:45 +0900 Subject: [PATCH] Upate to draft-15 * Add NGHTTP2_HTTP_1_1_REQUIRED error code * Allow transmission of WINDOW_UPDATE on reserved (remote) * Allow reception of WINDOW_UPDATE on reserved (local) * Treat frame larger than MAX_FRAME_SIZE as FRAME_SIZE_ERROR ALPN identifier is still h2-14 to continue interop, since draft-14 and -15 are binary compatible. The new error code was added in draft-15, but HTTP/2 allows extensions can freely add new error code, so it is not a problem. --- lib/includes/nghttp2/nghttp2.h | 6 +++++- lib/nghttp2_session.c | 6 +++--- src/app_helper.cc | 2 ++ src/http2.cc | 1 + tests/nghttp2_session_test.c | 22 +++++++++++++++++++++- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 68e9c3e4..7a8b254e 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -586,7 +586,11 @@ typedef enum { /** * INADEQUATE_SECURITY */ - NGHTTP2_INADEQUATE_SECURITY = 0x0c + NGHTTP2_INADEQUATE_SECURITY = 0x0c, + /** + * HTTP_1_1_REQUIRED + */ + NGHTTP2_HTTP_1_1_REQUIRED = 0x0d } nghttp2_error_code; /** diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 384c8c52..1aa41ede 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1314,7 +1314,7 @@ static int session_predicate_window_update_send if(stream->state == NGHTTP2_STREAM_CLOSING) { return NGHTTP2_ERR_STREAM_CLOSING; } - if(stream->state == NGHTTP2_STREAM_RESERVED) { + if(state_reserved_local(session, stream)) { return NGHTTP2_ERR_INVALID_STREAM_STATE; } return 0; @@ -3884,7 +3884,7 @@ static int session_on_stream_window_update_received } return 0; } - if(stream->state == NGHTTP2_STREAM_RESERVED) { + if(state_reserved_remote(session, stream)) { return session_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR, "WINDOW_UPADATE to reserved stream"); @@ -4467,7 +4467,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_PAYLOAD; rv = nghttp2_session_terminate_session_with_reason - (session, NGHTTP2_PROTOCOL_ERROR, "too large frame size"); + (session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size"); if(nghttp2_is_fatal(rv)) { return rv; diff --git a/src/app_helper.cc b/src/app_helper.cc index 2611a45d..94ba0ef7 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -81,6 +81,8 @@ const char* strstatus(uint32_t error_code) return "ENHANCE_YOUR_CALM"; case NGHTTP2_INADEQUATE_SECURITY: return "INADEQUATE_SECURITY"; + case NGHTTP2_HTTP_1_1_REQUIRED: + return "HTTP_1_1_REQUIRED"; default: return "UNKNOWN"; } diff --git a/src/http2.cc b/src/http2.cc index 7e2ced9a..44ad4212 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -69,6 +69,7 @@ std::string get_status_string(unsigned int status_code) case 415: return "415 Unsupported Media Type"; case 416: return "416 Requested Range Not Satisfiable"; case 417: return "417 Expectation Failed"; + case 421: return "421 Misdirected Request"; case 426: return "426 Upgrade Required"; case 428: return "428 Precondition Required"; case 429: return "429 Too Many Requests"; diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 5195d957..58a4eace 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2585,7 +2585,8 @@ void test_nghttp2_session_on_window_update_received(void) nghttp2_frame_window_update_free(&frame.window_update); - /* WINDOW_UPDATE against reserved stream is a connection error */ + /* Receiving WINDOW_UPDATE on reserved (remote) stream is a + connection error */ stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); @@ -2600,6 +2601,25 @@ void test_nghttp2_session_on_window_update_received(void) nghttp2_frame_window_update_free(&frame.window_update); nghttp2_session_del(session); + + /* Receiving WINDOW_UPDATE on reserved (local) stream is allowed */ + nghttp2_session_server_new(&session, &callbacks, &user_data); + + stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, + &pri_spec_default, + NGHTTP2_STREAM_RESERVED, NULL); + + nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, + 2, 4096); + + CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame)); + CU_ASSERT(!(session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND)); + + CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 4096 == stream->remote_window_size); + + nghttp2_frame_window_update_free(&frame.window_update); + + nghttp2_session_del(session); } void test_nghttp2_session_on_data_received(void)