]> granicus.if.org Git - apache/commitdiff
Merge r1770951, r1774008, r1774068, r1774069 from trunk:
authorJim Jagielski <jim@apache.org>
Tue, 13 Dec 2016 17:57:58 +0000 (17:57 +0000)
committerJim Jagielski <jim@apache.org>
Tue, 13 Dec 2016 17:57:58 +0000 (17:57 +0000)
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

CHANGES
STATUS
docs/manual/mod/mod_ratelimit.xml
modules/filters/mod_ratelimit.c

diff --git a/CHANGES b/CHANGES
index 6f6b7cb4dec080209d3b5c069cbc6e8fc314a854..964c51c55abfc29738b8e15cc65b1bd58d53804a 100644 (file)
--- 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 <ajv-etradanalhos vsta.org>,
+     Jim Jagielski]
+
   *) mod_socache_memcache: Provide memcache stats to mod_status.
      [Jim Jagielski]
 
diff --git a/STATUS b/STATUS
index ec300833f4b6aec5e6ad1ea0747348fa6d11463c..8eb246768c7132d40e2c52bd301cebd91e8dbaa9 100644 (file)
--- 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 ]
index 5cac06cbf846a7c4d18de4ce20f0c9fc11bf027e..973b8e1f0f0f282d151e0ef38c45d3c0fafedfb3 100644 (file)
@@ -30,6 +30,7 @@ the document to validate. -->
 <status>Extension</status>
 <sourcefile>mod_ratelimit.c</sourcefile>
 <identifier>ratelimit_module</identifier>
+<compatibility><code>rate-initial-burst</code> available in httpd 2.4.24 and later.</compatibility>
 
 <summary>
 
@@ -37,13 +38,25 @@ the document to validate. -->
 The connection speed to be simulated is specified, in KiB/s, using the environment
 variable <code>rate-limit</code>.</p>
 
+<p>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 <code>rate-initial-burst</code>.</p>
+
 <example><title>Example Configuration</title>
 <highlight language="config">
 &lt;Location "/downloads"&gt;
     SetOutputFilter RATE_LIMIT
     SetEnv rate-limit 400 
+    SetEnv rate-initial-burst 512
 &lt;/Location&gt;
 </highlight>
+
+<note type="warning">
+If the value specified for <code>rate-limit</code> causes integer overflow, the rate-limited will be disabled.
+If the value specified for <code>rate-limit-burst</code> causes integer overflow, the burst will be disabled.
+</note>
+
 </example>
 
 </summary>
index a2e9bd0197710ae321edc4e9a51a598601162a39..64283c76c3adca87abca45b456a7f02112daebd5 100644 (file)
@@ -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.");