diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 30 | ||||
-rw-r--r-- | lib/includes/nghttp2/nghttp2.h | 18 | ||||
-rw-r--r-- | lib/nghttp2_helper.c | 2 | ||||
-rw-r--r-- | lib/nghttp2_option.c | 5 | ||||
-rw-r--r-- | lib/nghttp2_option.h | 5 | ||||
-rw-r--r-- | lib/nghttp2_session.c | 59 | ||||
-rw-r--r-- | lib/nghttp2_session.h | 10 |
7 files changed, 98 insertions, 31 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 211c8e4..fda8dcb 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -34,6 +34,10 @@ set(NGHTTP2_RES "") set(STATIC_LIB "nghttp2_static") set(SHARED_LIB "nghttp2") +if(BUILD_SHARED_LIBS AND BUILD_STATIC_LIBS AND MSVC AND NOT STATIC_LIB_SUFFIX) + set(STATIC_LIB_SUFFIX "_static") +endif() + if(WIN32) configure_file( version.rc.in @@ -66,23 +70,23 @@ if(BUILD_SHARED_LIBS) endif() # Static library (for unittests because of symbol visibility) -add_library(${STATIC_LIB} STATIC ${NGHTTP2_SOURCES}) +if(BUILD_STATIC_LIBS) + add_library(${STATIC_LIB} STATIC ${NGHTTP2_SOURCES}) -set_target_properties(${STATIC_LIB} PROPERTIES - COMPILE_FLAGS "${WARNCFLAGS}" - VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} - ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX} -) + set_target_properties(${STATIC_LIB} PROPERTIES + COMPILE_FLAGS "${WARNCFLAGS}" + VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} + ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX} + ) -target_include_directories(${STATIC_LIB} INTERFACE - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes> - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes> - $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> -) + target_include_directories(${STATIC_LIB} INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes> + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + ) -target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB") + target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB") -if(BUILD_STATIC_LIBS) install(TARGETS ${STATIC_LIB} EXPORT ${EXPORT_SET}) list(APPEND nghttp2_exports ${STATIC_LIB}) endif() diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 8891760..92c3ccc 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -466,7 +466,12 @@ typedef enum { * exhaustion on server side to send these frames forever and does * not read network. */ - NGHTTP2_ERR_FLOODED = -904 + NGHTTP2_ERR_FLOODED = -904, + /** + * When a local endpoint receives too many CONTINUATION frames + * following a HEADER frame. + */ + NGHTTP2_ERR_TOO_MANY_CONTINUATIONS = -905, } nghttp2_error; /** @@ -3208,6 +3213,17 @@ nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, /** * @function * + * This function sets the maximum number of CONTINUATION frames + * following an incoming HEADER frame. If more than those frames are + * received, the remote endpoint is considered to be misbehaving and + * session will be closed. The default value is 8. + */ +NGHTTP2_EXTERN void nghttp2_option_set_max_continuations(nghttp2_option *option, + size_t val); + +/** + * @function + * * Initializes |*session_ptr| for client use. The all members of * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| * does not store |callbacks|. The |user_data| is an arbitrary user diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index 93dd475..b3563d9 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -336,6 +336,8 @@ const char *nghttp2_strerror(int error_code) { "closed"; case NGHTTP2_ERR_TOO_MANY_SETTINGS: return "SETTINGS frame contained more than the maximum allowed entries"; + case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: + return "Too many CONTINUATION frames following a HEADER frame"; default: return "Unknown error code"; } diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c index 43d4e95..53144b9 100644 --- a/lib/nghttp2_option.c +++ b/lib/nghttp2_option.c @@ -150,3 +150,8 @@ void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, option->stream_reset_burst = burst; option->stream_reset_rate = rate; } + +void nghttp2_option_set_max_continuations(nghttp2_option *option, size_t val) { + option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS; + option->max_continuations = val; +} diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h index 2259e18..c89cb97 100644 --- a/lib/nghttp2_option.h +++ b/lib/nghttp2_option.h @@ -71,6 +71,7 @@ typedef enum { NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13, NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, + NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16, } nghttp2_option_flag; /** @@ -99,6 +100,10 @@ struct nghttp2_option { */ size_t max_settings; /** + * NGHTTP2_OPT_MAX_CONTINUATIONS + */ + size_t max_continuations; + /** * Bitwise OR of nghttp2_option_flag to determine that which fields * are specified. */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 226cdd5..004a4df 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -497,6 +497,7 @@ static int session_new(nghttp2_session **session_ptr, (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN; (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM; (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS; + (*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS; if (option) { if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && @@ -585,6 +586,10 @@ static int session_new(nghttp2_session **session_ptr, option->stream_reset_burst, option->stream_reset_rate); } + + if (option->opt_set_mask & NGHTTP2_OPT_MAX_CONTINUATIONS) { + (*session_ptr)->max_continuations = option->max_continuations; + } } rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, @@ -979,7 +984,14 @@ static int session_attach_stream_item(nghttp2_session *session, return 0; } - return session_ob_data_push(session, stream); + rv = session_ob_data_push(session, stream); + if (rv != 0) { + nghttp2_stream_detach_item(stream); + + return rv; + } + + return 0; } static void session_detach_stream_item(nghttp2_session *session, @@ -1309,9 +1321,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || nghttp2_stream_in_dep_tree(stream)); + nghttp2_session_detach_idle_stream(session, stream); + if (nghttp2_stream_in_dep_tree(stream)) { assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)); - nghttp2_session_detach_idle_stream(session, stream); + rv = nghttp2_stream_dep_remove(stream); if (rv != 0) { return NULL; @@ -1471,6 +1485,21 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, DEBUGF("stream: stream(%p)=%d close\n", stream, stream->stream_id); + /* We call on_stream_close_callback even if stream->state is + NGHTTP2_STREAM_INITIAL. This will happen while sending request + HEADERS, a local endpoint receives RST_STREAM for that stream. It + may be PROTOCOL_ERROR, but without notifying stream closure will + hang the stream in a local endpoint. + */ + + if (session->callbacks.on_stream_close_callback) { + if (session->callbacks.on_stream_close_callback( + session, stream_id, error_code, session->user_data) != 0) { + + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + if (stream->item) { nghttp2_outbound_item *item; @@ -1488,21 +1517,6 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, } } - /* We call on_stream_close_callback even if stream->state is - NGHTTP2_STREAM_INITIAL. This will happen while sending request - HEADERS, a local endpoint receives RST_STREAM for that stream. It - may be PROTOCOL_ERROR, but without notifying stream closure will - hang the stream in a local endpoint. - */ - - if (session->callbacks.on_stream_close_callback) { - if (session->callbacks.on_stream_close_callback( - session, stream_id, error_code, session->user_data) != 0) { - - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - is_my_stream_id = nghttp2_session_is_my_stream_id(session, stream_id); /* pushed streams which is not opened yet is not counted toward max @@ -1559,6 +1573,11 @@ int nghttp2_session_destroy_stream(nghttp2_session *session, } } + if (stream->queued && + (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { + session_ob_data_remove(session, stream); + } + nghttp2_map_remove(&session->streams, stream->stream_id); nghttp2_stream_free(stream); nghttp2_mem_free(mem, stream); @@ -6812,6 +6831,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, } } session_inbound_frame_reset(session); + + session->num_continuations = 0; } break; } @@ -6933,6 +6954,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, } #endif /* DEBUGBUILD */ + if (++session->num_continuations > session->max_continuations) { + return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS; + } + readlen = inbound_frame_buf_read(iframe, in, last); in += readlen; diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index b119329..ef8f7b2 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -110,6 +110,10 @@ typedef struct { #define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 #define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 +/* The default max number of CONTINUATION frames following an incoming + HEADER frame. */ +#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8 + /* Internal state when receiving incoming frame */ typedef enum { /* Receiving frame header */ @@ -290,6 +294,12 @@ struct nghttp2_session { size_t max_send_header_block_length; /* The maximum number of settings accepted per SETTINGS frame. */ size_t max_settings; + /* The maximum number of CONTINUATION frames following an incoming + HEADER frame. */ + size_t max_continuations; + /* The number of CONTINUATION frames following an incoming HEADER + frame. This variable is reset when END_HEADERS flag is seen. */ + size_t num_continuations; /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ uint32_t next_stream_id; /* The last stream ID this session initiated. For client session, |