On Thu, Jun 7, 2018 at 9:21 AM, Yann Ylavic <ylavic....@gmail.com> wrote:
>
> Feel free to take what can serve you, or burn it ;)

Burn it! Here is v2, hopefully a less buggy :)
Index: modules/filters/mod_ratelimit.c
===================================================================
--- modules/filters/mod_ratelimit.c	(revision 1833084)
+++ modules/filters/mod_ratelimit.c	(working copy)
@@ -26,7 +26,6 @@
 
 typedef enum rl_state_e
 {
-    RATE_ERROR,
     RATE_LIMIT,
     RATE_FULLSPEED
 } rl_state_e;
@@ -36,6 +35,7 @@ typedef struct rl_ctx_t
     int speed;
     int chunk_size;
     int burst;
+    int do_sleep;
     rl_state_e state;
     apr_bucket_brigade *tmpbb;
     apr_bucket_brigade *holdingbb;
@@ -57,21 +57,12 @@ static void brigade_dump(request_rec *r, apr_bucke
 #endif /* RLFDEBUG */
 
 static apr_status_t
-rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
+rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 {
     apr_status_t rv = APR_SUCCESS;
     rl_ctx_t *ctx = f->ctx;
-    apr_bucket *fb;
-    int do_sleep = 0;
     apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc;
-    apr_bucket_brigade *bb = input_bb;
 
-    if (f->c->aborted) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01454) "rl: conn aborted");
-        apr_brigade_cleanup(bb);
-        return APR_ECONNABORTED;
-    }
-
     /* Set up our rl_ctx_t on first use */
     if (ctx == NULL) {
 
@@ -120,6 +111,7 @@ static apr_status_t
         ctx->state = RATE_LIMIT;
         ctx->speed = ratelimit;
         ctx->burst = burst;
+        ctx->do_sleep = 0;
 
         /* calculate how many bytes / interval we want to send */
         /* speed is bytes / second, so, how many  (speed / 1000 % interval) */
@@ -127,56 +119,40 @@ static apr_status_t
         ctx->tmpbb = apr_brigade_create(f->r->pool, ba);
         ctx->holdingbb = apr_brigade_create(f->r->pool, ba);
     }
+    else {
+        APR_BRIGADE_PREPEND(bb, ctx->holdingbb);
+    }
 
-    while (ctx->state != RATE_ERROR &&
-           (!APR_BRIGADE_EMPTY(bb) || !APR_BRIGADE_EMPTY(ctx->holdingbb))) {
+    while (!APR_BRIGADE_EMPTY(bb)) {
         apr_bucket *e;
 
-        if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) {
-            APR_BRIGADE_CONCAT(bb, ctx->holdingbb);
-        }
-
-        while (ctx->state == RATE_FULLSPEED && !APR_BRIGADE_EMPTY(bb)) {
+        if (ctx->state == RATE_FULLSPEED) {
             /* Find where we 'stop' going full speed. */
             for (e = APR_BRIGADE_FIRST(bb);
                  e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
                 if (AP_RL_BUCKET_IS_END(e)) {
-                    apr_bucket *f;
-                    f = APR_RING_LAST(&bb->list);
-                    APR_RING_UNSPLICE(e, f, link);
-                    APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f,
-                                         apr_bucket, link);
+                    apr_brigade_split_ex(bb, e, ctx->holdingbb);
                     ctx->state = RATE_LIMIT;
                     break;
                 }
             }
 
-            if (f->c->aborted) {
-                apr_brigade_cleanup(bb);
-                ctx->state = RATE_ERROR;
-                break;
-            }
-
-            fb = apr_bucket_flush_create(ba);
-            APR_BRIGADE_INSERT_TAIL(bb, fb);
+            e = apr_bucket_flush_create(ba);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
             rv = ap_pass_brigade(f->next, bb);
+            apr_brigade_cleanup(bb);
 
             if (rv != APR_SUCCESS) {
-                ctx->state = RATE_ERROR;
                 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01455)
                               "rl: full speed brigade pass failed.");
+                return rv;
             }
         }
-
-        while (ctx->state == RATE_LIMIT && !APR_BRIGADE_EMPTY(bb)) {
+        else {
             for (e = APR_BRIGADE_FIRST(bb);
                  e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
                 if (AP_RL_BUCKET_IS_START(e)) {
-                    apr_bucket *f;
-                    f = APR_RING_LAST(&bb->list);
-                    APR_RING_UNSPLICE(e, f, link);
-                    APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f,
-                                         apr_bucket, link);
+                    apr_brigade_split_ex(bb, e, ctx->holdingbb);
                     ctx->state = RATE_FULLSPEED;
                     break;
                 }
@@ -183,24 +159,8 @@ static apr_status_t
             }
 
             while (!APR_BRIGADE_EMPTY(bb)) {
-                apr_bucket *stop_point;
-                apr_off_t len = 0;
+                apr_off_t len = ctx->chunk_size + ctx->burst;
 
-                if (f->c->aborted) {
-                    apr_brigade_cleanup(bb);
-                    ctx->state = RATE_ERROR;
-                    break;
-                }
-
-                if (do_sleep) {
-                    apr_sleep(RATE_INTERVAL_MS * 1000);
-                }
-                else {
-                    do_sleep = 1;
-                }
-
-                apr_brigade_length(bb, 1, &len);
-
                 /*
                  * Pull next chunk of data; the initial amount is our
                  * burst allotment (if any) plus a chunk.  All subsequent
@@ -208,30 +168,40 @@ static apr_status_t
                  * 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);
+                rv = apr_brigade_partition(bb, len, &e);
                 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
-                    ctx->state = RATE_ERROR;
                     ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456)
                                   "rl: partition failed.");
-                    break;
+                    return rv;
                 }
-
-                if (stop_point != APR_BRIGADE_SENTINEL(bb)) {
-                    apr_bucket *f;
-                    apr_bucket *e = APR_BUCKET_PREV(stop_point);
-                    f = APR_RING_FIRST(&bb->list);
-                    APR_RING_UNSPLICE(f, e, link);
-                    APR_RING_SPLICE_HEAD(&ctx->tmpbb->list, f, e, apr_bucket,
-                                         link);
+                while (e != APR_BRIGADE_SENTINEL(bb)
+                       && APR_BUCKET_IS_METADATA(e)) {
+                    e = APR_BUCKET_NEXT(e);
                 }
+                if (e != APR_BRIGADE_SENTINEL(bb)) {
+                    apr_brigade_split_ex(bb, e, ctx->tmpbb);
+                }
                 else {
-                    APR_BRIGADE_CONCAT(ctx->tmpbb, bb);
+                    apr_brigade_length(bb, 1, &len);
                 }
 
-                fb = apr_bucket_flush_create(ba);
+#if defined(RLFDEBUG)
+                brigade_dump(f->r, bb);
+                brigade_dump(f->r, tmpbb);
+#endif /* RLFDEBUG */
 
-                APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
+                e = APR_BRIGADE_LAST(bb);
+                if (APR_BUCKET_IS_EOS(e)) {
+                    ap_remove_output_filter(f);
+                }
+                else if (!APR_BUCKET_IS_FLUSH(e)) {
+                    if (APR_BRIGADE_EMPTY(ctx->tmpbb)) {
+                        APR_BRIGADE_CONCAT(ctx->tmpbb, bb);
+                        break;
+                    }
+                    e = apr_bucket_flush_create(ba);
+                    APR_BRIGADE_INSERT_TAIL(bb, e);
+                }
 
                 /*
                  * Adjust the burst amount depending on how much
@@ -238,8 +208,6 @@ static apr_status_t
                  * 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) {
@@ -250,26 +218,38 @@ static apr_status_t
                     }
                 }
 
-#if defined(RLFDEBUG)
-                brigade_dump(f->r, ctx->tmpbb);
-                brigade_dump(f->r, bb);
-#endif /* RLFDEBUG */
+                if (ctx->do_sleep) {
+                    apr_sleep(RATE_INTERVAL_MS * 1000);
+                }
+                else {
+                    ctx->do_sleep = 1;
+                }
 
-                rv = ap_pass_brigade(f->next, ctx->tmpbb);
-                apr_brigade_cleanup(ctx->tmpbb);
+                rv = ap_pass_brigade(f->next, bb);
+                apr_brigade_cleanup(bb);
 
                 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.");
-                    break;
+                    return rv;
                 }
+
+                APR_BRIGADE_CONCAT(bb, ctx->tmpbb);
             }
         }
+
+        if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) {
+            APR_BRIGADE_CONCAT(bb, ctx->tmpbb);
+            APR_BRIGADE_CONCAT(bb, ctx->holdingbb);
+        }
     }
 
-    return rv;
+#if defined(RLFDEBUG)
+    brigade_dump(f->r, ctx->tmpbb);
+#endif /* RLFDEBUG */
+
+    return ap_save_brigade(f, &ctx->holdingbb, &ctx->tmpbb, f->r->pool);
 }
 
 

Reply via email to