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.");