@@ -78,6 +78,7 @@ typedef struct h2_config {
7878 apr_interval_time_t stream_timeout ;/* beam timeout */
7979 int max_data_frame_len ; /* max # bytes in a single h2 DATA frame */
8080 int max_hd_block_len ; /* max # bytes in a response header block */
81+ int max_stream_errors ; /* max # of tolerated stream errors */
8182 int proxy_requests ; /* act as forward proxy */
8283 int h2_websockets ; /* if mod_h2 negotiating WebSockets */
8384} h2_config ;
@@ -119,6 +120,7 @@ static h2_config defconf = {
119120 -1 , /* beam timeout */
120121 0 , /* max DATA frame len, 0 == no extra limit */
121122 0 , /* max header block len, 0 == no extra limit */
123+ 8 , /* max stream errors tolerated */
122124 0 , /* forward proxy */
123125 0 , /* WebSockets negotiation, enabled */
124126};
@@ -168,6 +170,7 @@ void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
168170 conf -> stream_timeout = DEF_VAL ;
169171 conf -> max_data_frame_len = DEF_VAL ;
170172 conf -> max_hd_block_len = DEF_VAL ;
173+ conf -> max_stream_errors = DEF_VAL ;
171174 conf -> proxy_requests = DEF_VAL ;
172175 conf -> h2_websockets = DEF_VAL ;
173176 return conf ;
@@ -220,6 +223,7 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
220223 n -> stream_timeout = H2_CONFIG_GET (add , base , stream_timeout );
221224 n -> max_data_frame_len = H2_CONFIG_GET (add , base , max_data_frame_len );
222225 n -> max_hd_block_len = H2_CONFIG_GET (add , base , max_hd_block_len );
226+ n -> max_stream_errors = H2_CONFIG_GET (add , base , max_stream_errors );
223227 n -> proxy_requests = H2_CONFIG_GET (add , base , proxy_requests );
224228 n -> h2_websockets = H2_CONFIG_GET (add , base , h2_websockets );
225229 return n ;
@@ -319,6 +323,9 @@ static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t v
319323 return H2_CONFIG_GET (conf , & defconf , h2_websockets );
320324 case H2_CONF_MAX_HEADER_BLOCK_LEN :
321325 return H2_CONFIG_GET (conf , & defconf , max_hd_block_len );
326+ case H2_CONF_MAX_STREAM_ERRORS :
327+ return H2_CONFIG_GET (conf , & defconf , max_stream_errors );
328+
322329 default :
323330 return DEF_VAL ;
324331 }
@@ -389,6 +396,9 @@ static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
389396 break ;
390397 case H2_CONF_MAX_HEADER_BLOCK_LEN :
391398 H2_CONFIG_SET (conf , max_hd_block_len , val );
399+ break ;
400+ case H2_CONF_MAX_STREAM_ERRORS :
401+ H2_CONFIG_SET (conf , max_stream_errors , val );
392402 default :
393403 break ;
394404 }
@@ -669,6 +679,17 @@ static const char *h2_conf_set_max_hd_block_len(cmd_parms *cmd,
669679 return NULL ;
670680}
671681
682+ static const char * h2_conf_set_max_stream_errors (cmd_parms * cmd ,
683+ void * dirconf , const char * value )
684+ {
685+ int val = (int )apr_atoi64 (value );
686+ if (val < 0 ) {
687+ return "value must be 0 or larger" ;
688+ }
689+ CONFIG_CMD_SET (cmd , dirconf , H2_CONF_MAX_STREAM_ERRORS , val );
690+ return NULL ;
691+ }
692+
672693static const char * h2_conf_set_session_extra_files (cmd_parms * cmd ,
673694 void * dirconf , const char * value )
674695{
@@ -1092,6 +1113,8 @@ const command_rec h2_cmds[] = {
10921113 RSRC_CONF , "maximum number of bytes in a single HTTP/2 DATA frame" ),
10931114 AP_INIT_TAKE1 ("H2MaxHeaderBlockLen" , h2_conf_set_max_hd_block_len , NULL ,
10941115 RSRC_CONF , "maximum number of bytes in a response header block" ),
1116+ AP_INIT_TAKE1 ("H2MaxStreamErrors" , h2_conf_set_max_stream_errors , NULL ,
1117+ RSRC_CONF , "maximum number of flow control errors tolerated" ),
10951118 AP_INIT_TAKE2 ("H2EarlyHint" , h2_conf_add_early_hint , NULL ,
10961119 OR_FILEINFO |OR_AUTHCFG , "add a a 'Link:' header for a 103 Early Hints response." ),
10971120 AP_INIT_TAKE1 ("H2ProxyRequests" , h2_conf_set_proxy_requests , NULL ,
0 commit comments