On 12/01/2008 06:12 AM, [EMAIL PROTECTED] wrote:
> Author: pquerna
> Date: Sun Nov 30 21:12:22 2008
> New Revision: 721965
>
> URL: http://svn.apache.org/viewvc?rev=721965&view=rev
> Log:
> Add a new module, mod_ratelimit, originally written at Joost, which can rate
> limit the outgoing bandwidth to a client.
>
> Added:
> httpd/httpd/trunk/modules/filters/mod_ratelimit.c (with props)
> httpd/httpd/trunk/modules/filters/mod_ratelimit.h (with props)
> Modified:
> httpd/httpd/trunk/modules/filters/config.m4
I guess you missed a change entry here.
> +static apr_status_t
> +rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_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, "rl: conn aborted");
> + apr_brigade_cleanup(bb);
> + return APR_ECONNABORTED;
> + }
> +
> + if (ctx == NULL) {
> +
> + /* no subrequests. */
> + if (f->r->main != NULL) {
> + ap_remove_output_filter(f);
> + return ap_pass_brigade(f->next, bb);
> + }
> +
> + const char *rl = apr_table_get(f->r->subprocess_env, "rate-limit");
> +
> + if (rl == NULL) {
> + ap_remove_output_filter(f);
> + return ap_pass_brigade(f->next, bb);
> + }
> +
> + /* first run, init stuff */
> + ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t));
> + f->ctx = ctx;
> + ctx->speed = 0;
> + ctx->state = RATE_LIMIT;
> +
> + /* rl is in kilo bytes / second */
> + ctx->speed = atoi(rl) * 1024;
> +
> + if (ctx->speed == 0) {
> + /* remove ourselves */
> + ap_remove_output_filter(f);
> + return ap_pass_brigade(f->next, bb);
> + }
> +
> + /* calculate how many bytes / interval we want to send */
> + /* speed is bytes / second, so, how many (speed / 1000 % interval)
> */
> + ctx->chunk_size = (ctx->speed / (1000 / RATE_INTERVAL_MS));
> + ctx->tmpbb = apr_brigade_create(f->r->pool, ba);
> + ctx->holdingbb = apr_brigade_create(f->r->pool, ba);
> + }
> +
> + while (ctx->state != RATE_ERROR &&
> + (!APR_BRIGADE_EMPTY(bb) || !APR_BRIGADE_EMPTY(ctx->holdingbb))) {
> + apr_bucket *e;
> +
> + if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) {
> + APR_BRIGADE_CONCAT(bb, ctx->holdingbb);
> + apr_brigade_cleanup(ctx->holdingbb);
> + }
> +
> + while (ctx->state == RATE_FULLSPEED && !APR_BRIGADE_EMPTY(bb)) {
> + /* Find where we 'stop' going full speed. */
> + for (e = APR_BRIGADE_FIRST(bb);
> + e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
> + if (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);
> + 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);
> + rv = ap_pass_brigade(f->next, bb);
> +
> + if (rv != APR_SUCCESS) {
> + ctx->state = RATE_ERROR;
> + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
> + "rl: full speed brigade pass failed.");
> + }
> + }
> +
> + while (ctx->state == RATE_LIMIT && !APR_BRIGADE_EMPTY(bb)) {
> + for (e = APR_BRIGADE_FIRST(bb);
> + e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
> + if (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);
> + ctx->state = RATE_FULLSPEED;
> + break;
> + }
> + }
> +
> + while (!APR_BRIGADE_EMPTY(bb)) {
> + apr_bucket *stop_point;
> + apr_off_t len = 0;
> +
> + if (f->c->aborted) {
> + apr_brigade_cleanup(bb);
> + ctx->state = RATE_ERROR;
Shouldn't we do a break or continue here?
> + }
> +
> + if (do_sleep) {
> + apr_sleep(RATE_INTERVAL_MS * 1000);
> + }
> + else {
> + do_sleep = 1;
> + }
> +
> + apr_brigade_length(bb, 1, &len);
> +
> + rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point);
> + if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
> + ctx->state = RATE_ERROR;
> + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
> + "rl: partition failed.");
> + break;
> + }
> +
> + 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);
> + }
> + else {
> + APR_BRIGADE_CONCAT(ctx->tmpbb, bb);
> + }
> +
> + fb = apr_bucket_flush_create(ba);
> +
> + APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
> +
> +#if 0
> + brigade_dump(f->r, ctx->tmpbb);
> + brigade_dump(f->r, bb);
> +#endif
> +
> + rv = ap_pass_brigade(f->next, ctx->tmpbb);
> + apr_brigade_cleanup(ctx->tmpbb);
> +
> + if (rv != APR_SUCCESS) {
> + ctx->state = RATE_ERROR;
> + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
> + "rl: brigade pass failed.");
> + break;
> + }
> + }
> + }
> + }
> +
> + return rv;
> +}
> +
Regards
RĂ¼diger