@@ -458,6 +458,7 @@ static int session_new(nghttp2_session **session_ptr,
458
458
459
459
(* session_ptr )-> max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN ;
460
460
(* session_ptr )-> max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM ;
461
+ (* session_ptr )-> max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS ;
461
462
462
463
if (option ) {
463
464
if ((option -> opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE ) &&
@@ -521,6 +522,11 @@ static int session_new(nghttp2_session **session_ptr,
521
522
if (option -> opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK ) {
522
523
(* session_ptr )-> max_outbound_ack = option -> max_outbound_ack ;
523
524
}
525
+
526
+ if ((option -> opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS ) &&
527
+ option -> max_settings ) {
528
+ (* session_ptr )-> max_settings = option -> max_settings ;
529
+ }
524
530
}
525
531
526
532
rv = nghttp2_hd_deflate_init2 (& (* session_ptr )-> hd_deflater ,
@@ -2494,14 +2500,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
2494
2500
static int session_update_connection_consumed_size (nghttp2_session * session ,
2495
2501
size_t delta_size );
2496
2502
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
-
2505
2503
/*
2506
2504
* Called after a frame is sent. This function runs
2507
2505
* on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2735,7 +2733,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
2735
2733
if (session -> opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE ) {
2736
2734
rv = session_update_connection_consumed_size (session , 0 );
2737
2735
} else {
2738
- rv = session_update_recv_connection_window_size (session , 0 );
2736
+ rv = nghttp2_session_update_recv_connection_window_size (session , 0 );
2739
2737
}
2740
2738
2741
2739
if (nghttp2_is_fatal (rv )) {
@@ -2761,7 +2759,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
2761
2759
if (session -> opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE ) {
2762
2760
rv = session_update_stream_consumed_size (session , stream , 0 );
2763
2761
} 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 );
2765
2764
}
2766
2765
2767
2766
if (nghttp2_is_fatal (rv )) {
@@ -5019,22 +5018,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
5019
5018
return 0 ;
5020
5019
}
5021
5020
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 ) {
5038
5025
int rv ;
5039
5026
rv = adjust_recv_window_size (& stream -> recv_window_size , delta_size ,
5040
5027
stream -> local_window_size );
@@ -5063,20 +5050,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
5063
5050
return 0 ;
5064
5051
}
5065
5052
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 ) {
5080
5055
int rv ;
5081
5056
rv = adjust_recv_window_size (& session -> recv_window_size , delta_size ,
5082
5057
session -> local_window_size );
@@ -5678,6 +5653,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
5678
5653
break ;
5679
5654
}
5680
5655
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
+
5681
5662
iframe -> state = NGHTTP2_IB_READ_SETTINGS ;
5682
5663
5683
5664
if (iframe -> payloadleft ) {
@@ -5688,6 +5669,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
5688
5669
iframe -> max_niv =
5689
5670
iframe -> frame .hd .length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1 ;
5690
5671
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
+
5691
5682
iframe -> iv = nghttp2_mem_malloc (mem , sizeof (nghttp2_settings_entry ) *
5692
5683
iframe -> max_niv );
5693
5684
@@ -6454,7 +6445,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
6454
6445
}
6455
6446
6456
6447
/* 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 );
6458
6449
if (nghttp2_is_fatal (rv )) {
6459
6450
return rv ;
6460
6451
}
@@ -6477,7 +6468,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
6477
6468
6478
6469
stream = nghttp2_session_get_stream (session , iframe -> frame .hd .stream_id );
6479
6470
if (stream ) {
6480
- rv = session_update_recv_stream_window_size (
6471
+ rv = nghttp2_session_update_recv_stream_window_size (
6481
6472
session , stream , readlen ,
6482
6473
iframe -> payloadleft ||
6483
6474
(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,
6524
6515
if (readlen > 0 ) {
6525
6516
ssize_t data_readlen ;
6526
6517
6527
- rv = session_update_recv_connection_window_size (session , readlen );
6518
+ rv = nghttp2_session_update_recv_connection_window_size (session ,
6519
+ readlen );
6528
6520
if (nghttp2_is_fatal (rv )) {
6529
6521
return rv ;
6530
6522
}
@@ -6533,7 +6525,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
6533
6525
return (ssize_t )inlen ;
6534
6526
}
6535
6527
6536
- rv = session_update_recv_stream_window_size (
6528
+ rv = nghttp2_session_update_recv_stream_window_size (
6537
6529
session , stream , readlen ,
6538
6530
iframe -> payloadleft ||
6539
6531
(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,
6634
6626
if (readlen > 0 ) {
6635
6627
/* Update connection-level flow control window for ignored
6636
6628
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 );
6638
6631
if (nghttp2_is_fatal (rv )) {
6639
6632
return rv ;
6640
6633
}
@@ -7454,6 +7447,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
7454
7447
if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH ) {
7455
7448
return NGHTTP2_ERR_INVALID_ARGUMENT ;
7456
7449
}
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
+ }
7457
7455
rv = nghttp2_frame_unpack_settings_payload2 (& iv , & niv , settings_payload ,
7458
7456
settings_payloadlen , mem );
7459
7457
if (rv != 0 ) {
0 commit comments