@@ -458,6 +458,7 @@ static int session_new(nghttp2_session **session_ptr,
458458
459459 (* session_ptr )-> max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN ;
460460 (* session_ptr )-> max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM ;
461+ (* session_ptr )-> max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS ;
461462
462463 if (option ) {
463464 if ((option -> opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE ) &&
@@ -521,6 +522,11 @@ static int session_new(nghttp2_session **session_ptr,
521522 if (option -> opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK ) {
522523 (* session_ptr )-> max_outbound_ack = option -> max_outbound_ack ;
523524 }
525+
526+ if ((option -> opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS ) &&
527+ option -> max_settings ) {
528+ (* session_ptr )-> max_settings = option -> max_settings ;
529+ }
524530 }
525531
526532 rv = nghttp2_hd_deflate_init2 (& (* session_ptr )-> hd_deflater ,
@@ -2494,14 +2500,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
24942500static int session_update_connection_consumed_size (nghttp2_session * session ,
24952501 size_t delta_size );
24962502
2497- static int session_update_recv_connection_window_size (nghttp2_session * session ,
2498- size_t delta_size );
2499-
2500- static int session_update_recv_stream_window_size (nghttp2_session * session ,
2501- nghttp2_stream * stream ,
2502- size_t delta_size ,
2503- int send_window_update );
2504-
25052503/*
25062504 * Called after a frame is sent. This function runs
25072505 * on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2735,7 +2733,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
27352733 if (session -> opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE ) {
27362734 rv = session_update_connection_consumed_size (session , 0 );
27372735 } else {
2738- rv = session_update_recv_connection_window_size (session , 0 );
2736+ rv = nghttp2_session_update_recv_connection_window_size (session , 0 );
27392737 }
27402738
27412739 if (nghttp2_is_fatal (rv )) {
@@ -2761,7 +2759,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
27612759 if (session -> opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE ) {
27622760 rv = session_update_stream_consumed_size (session , stream , 0 );
27632761 } else {
2764- rv = session_update_recv_stream_window_size (session , stream , 0 , 1 );
2762+ rv =
2763+ nghttp2_session_update_recv_stream_window_size (session , stream , 0 , 1 );
27652764 }
27662765
27672766 if (nghttp2_is_fatal (rv )) {
@@ -5019,22 +5018,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
50195018 return 0 ;
50205019}
50215020
5022- /*
5023- * Accumulates received bytes |delta_size| for stream-level flow
5024- * control and decides whether to send WINDOW_UPDATE to that stream.
5025- * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
5026- * be sent.
5027- *
5028- * This function returns 0 if it succeeds, or one of the following
5029- * negative error codes:
5030- *
5031- * NGHTTP2_ERR_NOMEM
5032- * Out of memory.
5033- */
5034- static int session_update_recv_stream_window_size (nghttp2_session * session ,
5035- nghttp2_stream * stream ,
5036- size_t delta_size ,
5037- int send_window_update ) {
5021+ int nghttp2_session_update_recv_stream_window_size (nghttp2_session * session ,
5022+ nghttp2_stream * stream ,
5023+ size_t delta_size ,
5024+ int send_window_update ) {
50385025 int rv ;
50395026 rv = adjust_recv_window_size (& stream -> recv_window_size , delta_size ,
50405027 stream -> local_window_size );
@@ -5063,20 +5050,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
50635050 return 0 ;
50645051}
50655052
5066- /*
5067- * Accumulates received bytes |delta_size| for connection-level flow
5068- * control and decides whether to send WINDOW_UPDATE to the
5069- * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
5070- * WINDOW_UPDATE will not be sent.
5071- *
5072- * This function returns 0 if it succeeds, or one of the following
5073- * negative error codes:
5074- *
5075- * NGHTTP2_ERR_NOMEM
5076- * Out of memory.
5077- */
5078- static int session_update_recv_connection_window_size (nghttp2_session * session ,
5079- size_t delta_size ) {
5053+ int nghttp2_session_update_recv_connection_window_size (nghttp2_session * session ,
5054+ size_t delta_size ) {
50805055 int rv ;
50815056 rv = adjust_recv_window_size (& session -> recv_window_size , delta_size ,
50825057 session -> local_window_size );
@@ -5678,6 +5653,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
56785653 break ;
56795654 }
56805655
5656+ /* Check the settings flood counter early to be safe */
5657+ if (session -> obq_flood_counter_ >= session -> max_outbound_ack &&
5658+ !(iframe -> frame .hd .flags & NGHTTP2_FLAG_ACK )) {
5659+ return NGHTTP2_ERR_FLOODED ;
5660+ }
5661+
56815662 iframe -> state = NGHTTP2_IB_READ_SETTINGS ;
56825663
56835664 if (iframe -> payloadleft ) {
@@ -5688,6 +5669,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
56885669 iframe -> max_niv =
56895670 iframe -> frame .hd .length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1 ;
56905671
5672+ if (iframe -> max_niv - 1 > session -> max_settings ) {
5673+ rv = nghttp2_session_terminate_session_with_reason (
5674+ session , NGHTTP2_ENHANCE_YOUR_CALM ,
5675+ "SETTINGS: too many setting entries" );
5676+ if (nghttp2_is_fatal (rv )) {
5677+ return rv ;
5678+ }
5679+ return (ssize_t )inlen ;
5680+ }
5681+
56915682 iframe -> iv = nghttp2_mem_malloc (mem , sizeof (nghttp2_settings_entry ) *
56925683 iframe -> max_niv );
56935684
@@ -6454,7 +6445,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
64546445 }
64556446
64566447 /* Pad Length field is subject to flow control */
6457- rv = session_update_recv_connection_window_size (session , readlen );
6448+ rv = nghttp2_session_update_recv_connection_window_size (session , readlen );
64586449 if (nghttp2_is_fatal (rv )) {
64596450 return rv ;
64606451 }
@@ -6477,7 +6468,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
64776468
64786469 stream = nghttp2_session_get_stream (session , iframe -> frame .hd .stream_id );
64796470 if (stream ) {
6480- rv = session_update_recv_stream_window_size (
6471+ rv = nghttp2_session_update_recv_stream_window_size (
64816472 session , stream , readlen ,
64826473 iframe -> payloadleft ||
64836474 (iframe -> frame .hd .flags & NGHTTP2_FLAG_END_STREAM ) == 0 );
@@ -6524,7 +6515,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
65246515 if (readlen > 0 ) {
65256516 ssize_t data_readlen ;
65266517
6527- rv = session_update_recv_connection_window_size (session , readlen );
6518+ rv = nghttp2_session_update_recv_connection_window_size (session ,
6519+ readlen );
65286520 if (nghttp2_is_fatal (rv )) {
65296521 return rv ;
65306522 }
@@ -6533,7 +6525,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
65336525 return (ssize_t )inlen ;
65346526 }
65356527
6536- rv = session_update_recv_stream_window_size (
6528+ rv = nghttp2_session_update_recv_stream_window_size (
65376529 session , stream , readlen ,
65386530 iframe -> payloadleft ||
65396531 (iframe -> frame .hd .flags & NGHTTP2_FLAG_END_STREAM ) == 0 );
@@ -6634,7 +6626,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
66346626 if (readlen > 0 ) {
66356627 /* Update connection-level flow control window for ignored
66366628 DATA frame too */
6637- rv = session_update_recv_connection_window_size (session , readlen );
6629+ rv = nghttp2_session_update_recv_connection_window_size (session ,
6630+ readlen );
66386631 if (nghttp2_is_fatal (rv )) {
66396632 return rv ;
66406633 }
@@ -7454,6 +7447,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
74547447 if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH ) {
74557448 return NGHTTP2_ERR_INVALID_ARGUMENT ;
74567449 }
7450+ /* SETTINGS frame contains too many settings */
7451+ if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH
7452+ > session -> max_settings ) {
7453+ return NGHTTP2_ERR_TOO_MANY_SETTINGS ;
7454+ }
74577455 rv = nghttp2_frame_unpack_settings_payload2 (& iv , & niv , settings_payload ,
74587456 settings_payloadlen , mem );
74597457 if (rv != 0 ) {
0 commit comments