From: Jim Jagielski Date: Tue, 13 Dec 2016 17:57:58 +0000 (+0000) Subject: Merge r1770951, r1774008, r1774068, r1774069 from trunk: X-Git-Tag: 2.4.24~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24f60b5289c27afea5cff9210bfd8cb51bc5a5f3;p=thirdparty%2Fapache%2Fhttpd.git Merge r1770951, r1774008, r1774068, r1774069 from trunk: Allow for initual burst at full speed Some "error" reporting if we overflow rate limit notes xhtml Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1774071 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 6f6b7cb4dec..964c51c55ab 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,10 @@ Changes with Apache 2.4.24 pollution by malicious clients, upstream servers or faulty modules. [Stefan Fritsch, Eric Covener, Yann Ylavic] + *) mod_ratelimit: Allow for initial "burst" amount at full speed before + throttling: PR 60145 [Andy Valencia , + Jim Jagielski] + *) mod_socache_memcache: Provide memcache stats to mod_status. [Jim Jagielski] diff --git a/STATUS b/STATUS index ec300833f4b..8eb246768c7 100644 --- a/STATUS +++ b/STATUS @@ -34,7 +34,7 @@ Release history: [NOTE that x.{odd}.z versions are strictly Alpha/Beta releases, while x.{even}.z versions are Stable/GA releases.] - 2.4.24 : In development. + 2.4.24 : In development. Jim proposes to T&R ~ Dec 15th. 2.4.23 : Tagged on June 30, 2016. Released on July 05, 2016. 2.4.22 : Tagged on June 20, 2016, not released. 2.4.21 : Tagged on June 16, 2016, not released. @@ -119,17 +119,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_ratelimit: Allow for initial burst of data before we start - throttling: PR 60145 - trunk patches: - https://svn.apache.org/r1770951 - https://svn.apache.org/r1774008 - 2.4.x patch: trunk works modulo CHANGES and next-number - +1: jim, ylavic, elukey - jailletc36: compatibility note missing in the XML file - jim: Will address during commit - elukey: the maximum value limitation for the new burst feature needs - to be documented. PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/docs/manual/mod/mod_ratelimit.xml b/docs/manual/mod/mod_ratelimit.xml index 5cac06cbf84..973b8e1f0f0 100644 --- a/docs/manual/mod/mod_ratelimit.xml +++ b/docs/manual/mod/mod_ratelimit.xml @@ -30,6 +30,7 @@ the document to validate. --> Extension mod_ratelimit.c ratelimit_module +rate-initial-burst available in httpd 2.4.24 and later. @@ -37,13 +38,25 @@ the document to validate. --> The connection speed to be simulated is specified, in KiB/s, using the environment variable rate-limit.

+

Optionally, an initial amount of burst data, in KiB, may be +configured to be passed at full speed before throttling to the +specified rate limit. This value is optional, and is set using +the environment variable rate-initial-burst.

+ Example Configuration <Location "/downloads"> SetOutputFilter RATE_LIMIT SetEnv rate-limit 400 + SetEnv rate-initial-burst 512 </Location> + + +If the value specified for rate-limit causes integer overflow, the rate-limited will be disabled. +If the value specified for rate-limit-burst causes integer overflow, the burst will be disabled. + +
diff --git a/modules/filters/mod_ratelimit.c b/modules/filters/mod_ratelimit.c index a2e9bd01977..64283c76c3a 100644 --- a/modules/filters/mod_ratelimit.c +++ b/modules/filters/mod_ratelimit.c @@ -35,12 +35,13 @@ typedef struct rl_ctx_t { int speed; int chunk_size; + int burst; rl_state_e state; apr_bucket_brigade *tmpbb; apr_bucket_brigade *holdingbb; } rl_ctx_t; -#if 0 +#if defined(RLFDEBUG) static void brigade_dump(request_rec *r, apr_bucket_brigade *bb) { apr_bucket *e; @@ -53,7 +54,7 @@ static void brigade_dump(request_rec *r, apr_bucket_brigade *bb) } } -#endif +#endif /* RLFDEBUG */ static apr_status_t rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) @@ -71,10 +72,12 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) return APR_ECONNABORTED; } + /* Set up our rl_ctx_t on first use */ if (ctx == NULL) { const char *rl = NULL; int ratelimit; + int burst = 0; /* no subrequests. */ if (f->r->main != NULL) { @@ -82,6 +85,7 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) return ap_pass_brigade(f->next, bb); } + /* Configuration: rate limit */ rl = apr_table_get(f->r->subprocess_env, "rate-limit"); if (rl == NULL) { @@ -93,15 +97,29 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) ratelimit = atoi(rl) * 1024; if (ratelimit <= 0) { /* remove ourselves */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, + APLOGNO(03488) "rl: disabling: rate-limit = %s (too high?)", rl); ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } - /* first run, init stuff */ + /* Configuration: optional initial burst */ + rl = apr_table_get(f->r->subprocess_env, "rate-initial-burst"); + if (rl != NULL) { + burst = atoi(rl) * 1024; + if (burst <= 0) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, + APLOGNO(03489) "rl: disabling burst: rate-initial-burst = %s (too high?)", rl); + burst = 0; + } + } + + /* Set up our context */ ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t)); f->ctx = ctx; ctx->state = RATE_LIMIT; ctx->speed = ratelimit; + ctx->burst = burst; /* calculate how many bytes / interval we want to send */ /* speed is bytes / second, so, how many (speed / 1000 % interval) */ @@ -183,7 +201,15 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) apr_brigade_length(bb, 1, &len); - rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point); + /* + * Pull next chunk of data; the initial amount is our + * burst allotment (if any) plus a chunk. All subsequent + * iterations are just chunks with whatever remaining + * burst amounts we have left (in case not done in the + * first bucket). + */ + rv = apr_brigade_partition(bb, + ctx->chunk_size + ctx->burst, &stop_point); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456) @@ -207,15 +233,33 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb); -#if 0 + /* + * Adjust the burst amount depending on how much + * we've done up to now. + */ + if (ctx->burst) { + len = ctx->burst; + apr_brigade_length(ctx->tmpbb, 1, &len); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, + APLOGNO(03485) "rl: burst %d; len %"APR_OFF_T_FMT, ctx->burst, len); + if (len < ctx->burst) { + ctx->burst -= len; + } + else { + ctx->burst = 0; + } + } + +#if defined(RLFDEBUG) brigade_dump(f->r, ctx->tmpbb); brigade_dump(f->r, bb); -#endif +#endif /* RLFDEBUG */ rv = ap_pass_brigade(f->next, ctx->tmpbb); apr_brigade_cleanup(ctx->tmpbb); if (rv != APR_SUCCESS) { + /* Most often, user disconnects from stream */ ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457) "rl: brigade pass failed.");