View | Details | Raw Unified | Return to bug 62362
Collapse All | Expand All

(-)modules/filters/mod_ratelimit.c (-37 / +54 lines)
Lines 36-41 Link Here
36
    int speed;
36
    int speed;
37
    int chunk_size;
37
    int chunk_size;
38
    int burst;
38
    int burst;
39
    int do_sleep;
39
    rl_state_e state;
40
    rl_state_e state;
40
    apr_bucket_brigade *tmpbb;
41
    apr_bucket_brigade *tmpbb;
41
    apr_bucket_brigade *holdingbb;
42
    apr_bucket_brigade *holdingbb;
Lines 62-68 Link Here
62
    apr_status_t rv = APR_SUCCESS;
63
    apr_status_t rv = APR_SUCCESS;
63
    rl_ctx_t *ctx = f->ctx;
64
    rl_ctx_t *ctx = f->ctx;
64
    apr_bucket *fb;
65
    apr_bucket *fb;
65
    int do_sleep = 0;
66
    apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc;
66
    apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc;
67
    apr_bucket_brigade *bb = input_bb;
67
    apr_bucket_brigade *bb = input_bb;
Lines 120-125 Link Here
120
        ctx->state = RATE_LIMIT;
120
        ctx->state = RATE_LIMIT;
121
        ctx->speed = ratelimit;
121
        ctx->speed = ratelimit;
122
        ctx->burst = burst;
122
        ctx->burst = burst;
123
        ctx->do_sleep = 0;
123
        /* calculate how many bytes / interval we want to send */
124
        /* calculate how many bytes / interval we want to send */
124
        /* speed is bytes / second, so, how many  (speed / 1000 % interval) */
125
        /* speed is bytes / second, so, how many  (speed / 1000 % interval) */
Lines 185-190 Link Here
185
            while (!APR_BRIGADE_EMPTY(bb)) {
186
            while (!APR_BRIGADE_EMPTY(bb)) {
186
                apr_bucket *stop_point;
187
                apr_bucket *stop_point;
187
                apr_off_t len = 0;
188
                apr_off_t len = 0;
189
                apr_off_t len_tmp = 0;
188
                if (f->c->aborted) {
190
                if (f->c->aborted) {
189
                    apr_brigade_cleanup(bb);
191
                    apr_brigade_cleanup(bb);
Lines 192-238 Link Here
192
                    break;
194
                    break;
193
                }
195
                }
194
                if (do_sleep) {
196
                if (ctx->do_sleep) {
195
                    apr_sleep(RATE_INTERVAL_MS * 1000);
197
                    apr_sleep(RATE_INTERVAL_MS * 1000);
196
                }
198
                }
197
                else {
199
                else {
198
                    do_sleep = 1;
200
                    ctx->do_sleep = 1;
199
                }
201
                }
200
                apr_brigade_length(bb, 1, &len);
202
                apr_brigade_length(bb, 1, &len);
203
                apr_brigade_length(ctx->tmpbb, 1, &len_tmp);
201
                /*
204
                /*
202
                 * Pull next chunk of data; the initial amount is our
205
                 * If the buckets to be rate limited spans multiple brigades
203
                 * burst allotment (if any) plus a chunk.  All subsequent
206
                 * some buffering is needed. The idea is to pass buckets down
204
                 * iterations are just chunks with whatever remaining
207
                 * the chain (and flush) only when the length of the ctx->tmpbb
205
                 * burst amounts we have left (in case not done in the
208
                 * reaches ctx->chunk_size. If EOS is found as last bucket in
206
                 * first bucket).
209
                 * a brigade then ctx->tmpbb will be passed even if not reaching
210
                 * chunk_size. The buckets are also setaside properly via
211
                 * ap_save_brigade to avoid any inconsistency while buffering
212
                 * buckets between filter invocations.
207
                 */
213
                 */
208
                rv = apr_brigade_partition(bb,
214
                if (len_tmp + len >= ctx->chunk_size + ctx->burst) {
209
                    ctx->chunk_size + ctx->burst, &stop_point);
215
                    rv = apr_brigade_partition(bb,
210
                if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
216
                        ctx->chunk_size + ctx->burst - len_tmp, &stop_point);
211
                    ctx->state = RATE_ERROR;
217
                    if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
212
                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456)
218
                        ctx->state = RATE_ERROR;
213
                                  "rl: partition failed.");
219
                        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456)
214
                    break;
220
                                      "rl: partition failed.");
215
                }
221
                        break;
222
                    }
216
                if (stop_point != APR_BRIGADE_SENTINEL(bb)) {
223
                    if (stop_point != APR_BRIGADE_SENTINEL(bb)) {
217
                    apr_bucket *f;
224
                        apr_bucket_brigade* bb_tail;
218
                    apr_bucket *e = APR_BUCKET_PREV(stop_point);
225
                        bb_tail = apr_brigade_split(bb, stop_point);
219
                    f = APR_RING_FIRST(&bb->list);
226
                        ap_save_brigade(f, &(ctx->tmpbb), &bb, f->r->pool);
220
                    APR_RING_UNSPLICE(f, e, link);
227
                        bb = bb_tail;
221
                    APR_RING_SPLICE_HEAD(&ctx->tmpbb->list, f, e, apr_bucket,
222
                                         link);
223
                }
224
                else {
225
                    APR_BRIGADE_CONCAT(ctx->tmpbb, bb);
226
                }
227
                fb = apr_bucket_flush_create(ba);
228
                    }
229
                    else {
230
                        ap_save_brigade(f, &(ctx->tmpbb), &bb, f->r->pool);
231
                    }
228
                APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
232
                    fb = apr_bucket_flush_create(ba);
233
                    APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
234
                } else {
235
                    ap_save_brigade(f, &(ctx->tmpbb), &bb, f->r->pool);
236
                }
237
229
                /*
238
                /*
230
                 * Adjust the burst amount depending on how much
239
                 * Adjust the burst amount depending on how much
231
                 * we've done up to now.
240
                 * we've done up to now.
Lines 255-269 Link Here
255
                brigade_dump(f->r, bb);
264
                brigade_dump(f->r, bb);
256
#endif /* RLFDEBUG */
265
#endif /* RLFDEBUG */
257
                rv = ap_pass_brigade(f->next, ctx->tmpbb);
266
                apr_brigade_length(ctx->tmpbb, 1, &len_tmp);
258
                apr_brigade_cleanup(ctx->tmpbb);
259
                if (rv != APR_SUCCESS) {
267
                if ((len_tmp == ctx->chunk_size + ctx->burst)
260
                    /* Most often, user disconnects from stream */
268
                    || (len_tmp > 0 && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(ctx->tmpbb)))) {
261
                    ctx->state = RATE_ERROR;
269
                    rv = ap_pass_brigade(f->next, ctx->tmpbb);
262
                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457)
270
                    apr_brigade_cleanup(ctx->tmpbb);
263
                                  "rl: brigade pass failed.");
271
264
                    break;
272
                    if (rv != APR_SUCCESS) {
273
                        /* Most often, user disconnects from stream */
274
                        ctx->state = RATE_ERROR;
275
                        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457)
276
                                      "rl: brigade pass failed.");
277
                        break;
278
                    }
279
                    ctx->do_sleep = 1;
280
                } else {
281
                    ctx->do_sleep = 0;
265
                }
282
                }
266
            }
283
            }
267
        }
284
        }

Return to bug 62362