httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@covalent.net
Subject Re: [PATCH] final brigade buffering
Date Wed, 07 Feb 2001 15:59:35 GMT

Has anybody reviewed this yet?  I believe I have covered all of the
problems with the previous patches, and have done it in a way that is
useful for any program to use.  I am 99.9% sure that this also solves the
problem for mod_perl, mod_snake, mod_proxy, and the other modules.  I know
this solves the Apache header problem with less of a hack.

Since we aren't freezing the tree, I would like to get this committed.

Ryan

On Mon, 5 Feb 2001 rbb@covalent.net wrote:

> 
> This is the final brigade buffering patch.  What it basically does.  We
> use a simple heap bucket to buffer the data.  Whenever we fill a buffer,
> we automatically flush the entire brigade, using a flush function from the
> brigade itself.  We don't copy unless we can copy the entire string into
> the brigade with a single copy.
> 
> The only remaining complaint that I know of with this patch, is that it
> forces handlers to use r->bb as their brigade if they want to make sure
> that the data is never sent out of order.  This also removes the OLD_WRITE
> buffer, and it begins to remove some of the other buffering logic we have
> added.
> 
> This also allows modules like mod_perl to remove their special buffering
> logic.  I would really like to get this committed.  I will not even try to
> say that this code is bug free, but it has served a lot of pages very
> cleanly with this patch now.
> 
> Since we are no longer freezing the tree, I would like to get this in
> soon.
> 
> Ryan
> 
> 
> Index: include/http_protocol.h
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/include/http_protocol.h,v
> retrieving revision 1.51
> diff -u -d -b -w -u -r1.51 http_protocol.h
> --- include/http_protocol.h	2001/02/05 03:31:43	1.51
> +++ include/http_protocol.h	2001/02/06 05:19:31
> @@ -88,13 +88,13 @@
>  /**
>   * Send the minimal part of an HTTP response header.
>   * @param r The current request
> - * @param buf The buffer to add the header to.
> + * @param bb The brigade to add the header to.
>   * @warning Modules should be very careful about using this, and should 
>   *          prefer ap_send_http_header().  Much of the HTTP/1.1 implementation 
>   *          correctness depends on code in ap_send_http_header().
> - * @deffunc void ap_basic_http_header(request_rec *r, char *buf)
> + * @deffunc void ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb)
>   */
> -AP_DECLARE(void) ap_basic_http_header(request_rec *r, char *buf);
> +AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb);
>  
>  /**
>   * Send the Status-Line and header fields for HTTP response
> @@ -310,7 +310,11 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_rputc(int c, request_rec *r)
>   */
> -AP_DECLARE(int) ap_rputc(int c, request_rec *r);
> +#define ap_rputc(c, r) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fputc(r->output_filters, r->bb, c)
>  /**
>   * Output a string for the current request
>   * @param str The string to output
> @@ -318,7 +322,11 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_rputs(const char *str, request_rec *r)
>   */
> -AP_DECLARE(int) ap_rputs(const char *str, request_rec *r);
> +#define ap_rputs(str, r) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fputs(r->output_filters, r->bb, str)
>  /**
>   * Write a buffer for the current request
>   * @param buf The buffer to write
> @@ -327,7 +335,11 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_rwrite(const void *buf, int nbyte, request_rec *r)
>   */
> -AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r);
> +#define ap_rwrite(str, n, r) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fwrite(r->output_filters, r->bb, str, n)
>  /**
>   * Write an unspecified number of strings to the request
>   * @param r The current request
> @@ -335,7 +347,11 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_rvputs(request_rec *r, ...)
>   */
> -AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r,...);
> +#define ap_rvputs(r, args...) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fvputs(r->output_filters, r->bb, ##args)
>  /**
>   * Output data to the client in a printf format
>   * @param r The current request
> @@ -344,7 +360,11 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_vrprintf(request_rec *r, const char *fmt, va_list vlist)
>   */
> -AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list vlist);
> +#define ap_vrprintf(r, fmt, vlist) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_vfprintf(r->output_filters, r->bb, fmt, vlist)
>  /**
>   * Output data to the client in a printf format
>   * @param r The current request
> @@ -353,15 +373,22 @@
>   * @return The number of bytes sent
>   * @deffunc int ap_rprintf(request_rec *r, const char *fmt, ...)
>   */
> -AP_DECLARE_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt,...)
> -				__attribute__((format(printf,2,3)));
> +#define ap_rprintf(r, fmt, args...) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fprintf(r->output_filters, r->bb, fmt, ##args)
>  /**
>   * Flush all of the data for the current request to the client
>   * @param r The current request
>   * @return The number of bytes sent
>   * @deffunc int ap_rflush(request_rec *r)
>   */
> -AP_DECLARE(int) ap_rflush(request_rec *r);
> +#define ap_rflush(r) \
> +    if (!r->bb) { \
> +        r->bb = apr_brigade_create(r->pool); \
> +    } \
> +    ap_fflush(r->output_filters, r->bb)
>  
>  /**
>   * Index used in custom_responses array for a specific error code
> Index: include/httpd.h
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/include/httpd.h,v
> retrieving revision 1.134
> diff -u -d -b -w -u -r1.134 httpd.h
> --- include/httpd.h	2001/02/05 12:55:11	1.134
> +++ include/httpd.h	2001/02/06 05:19:31
> @@ -86,6 +86,7 @@
>  #include "apr_pools.h"
>  #include "apr_time.h"
>  #include "apr_network_io.h"
> +#include "apr_buckets.h"
>  
>  #ifdef CORE_PRIVATE
>  
> @@ -798,6 +799,8 @@
>      /** A flag to determine if the eos bucket has been sent yet
>       *  @defvar int eos_sent */
>      int eos_sent;
> +
> +    apr_bucket_brigade *bb;
>  
>  /* Things placed at the end of the record to avoid breaking binary
>   * compatibility.  It would be nice to remember to reorder the entire
> Index: include/util_filter.h
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/include/util_filter.h,v
> retrieving revision 1.38
> diff -u -d -b -w -u -r1.38 util_filter.h
> --- include/util_filter.h	2001/02/03 20:25:13	1.38
> +++ include/util_filter.h	2001/02/06 05:19:31
> @@ -393,6 +393,16 @@
>  AP_DECLARE(apr_status_t) ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **save_to,
>                                           apr_bucket_brigade **b);    
>  
> +AP_DECLARE(apr_status_t) ap_fwrite(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                  const char *str, apr_size_t nbyte); 
> +AP_DECLARE(apr_status_t) ap_fputs(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                  const char *str); 
> +AP_DECLARE(apr_status_t) ap_fputc(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                  char str); 
> +AP_DECLARE(apr_status_t) ap_fvputs(ap_filter_t *f, apr_bucket_brigade *bb, ...);
> +AP_DECLARE(apr_status_t) ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char
*fmt, ...);
> +
> +
>  #ifdef __cplusplus
>  }
>  #endif
> Index: modules/http/http_core.c
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/modules/http/http_core.c,v
> retrieving revision 1.254
> diff -u -d -b -w -u -r1.254 http_core.c
> --- modules/http/http_core.c	2001/02/05 18:28:47	1.254
> +++ modules/http/http_core.c	2001/02/06 05:19:35
> @@ -3593,8 +3593,6 @@
>                                AP_FTYPE_CONTENT);
>      ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
>      ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONTENT);
> -    ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
> -                              AP_FTYPE_CONTENT - 1);
>  }
>  
>  AP_DECLARE_DATA module core_module = {
> Index: modules/http/http_protocol.c
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/modules/http/http_protocol.c,v
> retrieving revision 1.289
> diff -u -d -b -w -u -r1.289 http_protocol.c
> --- modules/http/http_protocol.c	2001/02/01 21:54:18	1.289
> +++ modules/http/http_protocol.c	2001/02/06 05:19:38
> @@ -1587,13 +1587,15 @@
>  
>  static void end_output_stream(request_rec *r)
>  {
> -    apr_bucket_brigade *bb;
>      apr_bucket *b;
>  
> -    bb = apr_brigade_create(r->pool);
> +    if (!r->bb) {
> +        r->bb = apr_brigade_create(r->pool);
> +    }
> +
>      b = apr_bucket_create_eos();
> -    APR_BRIGADE_INSERT_TAIL(bb, b);
> -    ap_pass_brigade(r->output_filters, bb);
> +    APR_BRIGADE_INSERT_TAIL(r->bb, b);
> +    ap_pass_brigade(r->output_filters, r->bb);
>  }
>  
>  void ap_finalize_sub_req_protocol(request_rec *sub)
> @@ -1792,7 +1794,7 @@
>  
>  typedef struct header_struct {
>      request_rec *r;
> -    char *buf;
> +    apr_bucket_brigade *bb;
>  } header_struct;
>  
>  /* Send a single HTTP header field to the client.  Note that this function
> @@ -1807,16 +1809,7 @@
>  
>      headfield = apr_pstrcat(h->r->pool, fieldname, ": ", fieldval, CRLF, NULL);
>      ap_xlate_proto_to_ascii(headfield, strlen(headfield));
> -    apr_cpystrn(h->buf, headfield, strlen(headfield) + 1);
> -    h->buf += strlen(headfield);
> -    return 1;
> -}
> -
> -static int compute_header_len(apr_size_t *length, const char *fieldname, 
> -                              const char *fieldval)
> -{
> -    /* The extra five are for ": " and CRLF, plus one for a '\0'. */
> -    *length = *length + strlen(fieldname) + strlen(fieldval) + 6;
> +    apr_brigade_write(h->bb, headfield, strlen(headfield) + 1);
>      return 1;
>  }
>  
> @@ -1844,7 +1837,7 @@
>      }
>  }
>  
> -static void basic_http_header(request_rec *r, char *buf, const char *protocol)
> +static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, const char *protocol)
>  {
>      char *date = NULL;
>      char *tmp;
> @@ -1857,14 +1850,13 @@
>  
>      tmp = apr_pstrcat(r->pool, protocol, " ", r->status_line, CRLF, NULL);
>      ap_xlate_proto_to_ascii(tmp, strlen(tmp));
> -    apr_cpystrn(buf, tmp, strlen(tmp) + 1);
> -    buf += strlen(tmp);
> +    apr_brigade_write(bb, tmp, strlen(tmp) + 1);
>  
>      date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
>      apr_rfc822_date(date, r->request_time);
>  
>      h.r = r;
> -    h.buf = buf;
> +    h.bb = bb;
>      form_header_field(&h, "Date", date);
>      form_header_field(&h, "Server", ap_get_server_version());
>  
> @@ -1872,12 +1864,12 @@
>      apr_table_unset(r->headers_out, "Server");
>  }
>  
> -AP_DECLARE(void) ap_basic_http_header(request_rec *r, char *buf)
> +AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb)
>  {
>      const char *protocol;
>  
>      basic_http_header_check(r, &protocol);
> -    basic_http_header(r, buf, protocol);
> +    basic_http_header(r, bb, protocol);
>  }
>  
>  /* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
> @@ -1897,18 +1889,19 @@
>   * It is more expensive to check the User-Agent than it is to just add the
>   * bytes, so we haven't used the BrowserMatch feature here.
>   */
> -static void terminate_header(char *buf)
> +static void terminate_header(apr_bucket_brigade *bb)
>  {
> -    int len = strlen(buf);
> -    char *headfield = buf + len;
>      char *tmp = "X-Pad: avoid browser bug" CRLF;
> +    char *crlf = CRLF;
> +    apr_bucket *b = APR_BRIGADE_LAST(bb);
> +    apr_bucket_shared *s = b->data;
>  
> -    if (len >= 255 && len <= 257) {
> -        apr_cpystrn(headfield, tmp, strlen(tmp) + 1);
> -        headfield += strlen(tmp);
> +    if (s->end >= 255 && s->end <= 257) {
> +        ap_xlate_proto_to_ascii(tmp, strlen(tmp));
> +        apr_brigade_write(bb, tmp, strlen(tmp) + 1);
>      }
> -    apr_cpystrn(headfield, CRLF, strlen(CRLF) + 1);
> -    ap_xlate_proto_to_ascii(buf + len, strlen(buf + len));
> +    ap_xlate_proto_to_ascii(crlf, strlen(crlf));
> +    apr_brigade_write(bb, crlf, strlen(crlf) + 1);
>  }
>  
>  /*
> @@ -2154,42 +2147,28 @@
>  
>  int ap_send_http_options(request_rec *r)
>  {
> -    char *buff;
> -    apr_bucket *b;
> -    apr_bucket_brigade *bb;
> -    apr_size_t len = 0;
> +    apr_bucket_brigade *bb = apr_brigade_create(r->pool);
>      header_struct h;
>  
>      if (r->assbackwards)
>          return DECLINED;
> -
> -    apr_table_do((int (*) (void *, const char *, const char *)) compute_header_len,
> -                 (void *) &len, r->headers_out, NULL);
>      
> -    /* Need to add a fudge factor so that the CRLF at the end of the headers
> -     * and the basic http headers don't overflow this buffer.
> -     */
> -    len += strlen(ap_get_server_version()) + 100;
> -    buff = apr_pcalloc(r->pool, len);
> -    ap_basic_http_header(r, buff);
> +    ap_basic_http_header(r, bb);
>  
>      apr_table_setn(r->headers_out, "Content-Length", "0");
>      apr_table_setn(r->headers_out, "Allow", make_allow(r));
>      ap_set_keepalive(r);
>  
>      h.r = r;
> -    h.buf = buff;
> +    h.bb = bb;
>  
>      apr_table_do((int (*) (void *, const char *, const char *)) form_header_field,
>               (void *) &h, r->headers_out, NULL);
>  
> -    terminate_header(buff);
> +    terminate_header(bb);
>  
>      r->bytes_sent = 0;
>  
> -    bb = apr_brigade_create(r->pool);
> -    b = apr_bucket_create_pool(buff, strlen(buff), r->pool);
> -    APR_BRIGADE_INSERT_TAIL(bb, b);
>      ap_pass_brigade(r->output_filters, bb);
>  
>      return OK;
> @@ -2462,11 +2441,10 @@
>      int i;
>      char *date = NULL;
>      request_rec *r = f->r;
> -    char *buff, *buff_start;
>      const char *clheader;
>      const char *protocol;
>      apr_bucket *e;
> -    apr_bucket_brigade *b2;
> +    apr_bucket_brigade *b2 = apr_brigade_create(r->pool);
>      apr_size_t len = 0;
>      header_struct h;
>      header_filter_ctx *ctx = f->ctx;
> @@ -2483,7 +2461,7 @@
>      }
>  
>      APR_BRIGADE_FOREACH(e, b) {
> -        if (APR_BRIGADE_FIRST(b)->type == &ap_bucket_type_error) {
> +        if (e->type == &ap_bucket_type_error) {
>              ap_bucket_error *eb = e->data;
>  
>              ap_die(eb->status, r);
> @@ -2580,33 +2558,11 @@
>          !strcmp(clheader, "0")) {
>          apr_table_unset(r->headers_out, "Content-Length");
>      }
> -
> -    if (r->status == HTTP_NOT_MODIFIED) {
> -        apr_table_do((int (*)(void *, const char *, const char *)) compute_header_len,
> -                    (void *) &len, r->headers_out,
> -                    "Connection",
> -                    "Keep-Alive",
> -                    "ETag",
> -                    "Content-Location",
> -                    "Expires",
> -                    "Cache-Control",
> -                    "Vary",
> -                    "Warning",
> -                    "WWW-Authenticate",
> -                    "Proxy-Authenticate",
> -                    NULL);
> -    }
> -    else {
> -        apr_table_do((int (*) (void *, const char *, const char *)) compute_header_len,
> -                 (void *) &len, r->headers_out, NULL);
> -    }
>      
> -    buff_start = buff = apr_pcalloc(r->pool, len);
> -    basic_http_header(r, buff, protocol);
> -    buff += strlen(buff);
> +    basic_http_header(r, b2, protocol);
>  
>      h.r = r;
> -    h.buf = buff;
> +    h.bb = b2;
>  
>      if (r->status == HTTP_NOT_MODIFIED) {
>          apr_table_do((int (*)(void *, const char *, const char *)) form_header_field,
> @@ -2628,13 +2584,10 @@
>  		 (void *) &h, r->headers_out, NULL);
>      }
>  
> -    terminate_header(buff);
> +    terminate_header(b2);
>  
>      r->sent_bodyct = 1;         /* Whatever follows is real body stuff... */
>  
> -    b2 = apr_brigade_create(r->pool);
> -    e = apr_bucket_create_pool(buff_start, strlen(buff_start), r->pool);
> -    APR_BRIGADE_INSERT_HEAD(b2, e);
>      ap_pass_brigade(f->next, b2);
>  
>      if (r->header_only) {
> @@ -2985,244 +2938,6 @@
>      return mm->size; /* XXX - change API to report apr_status_t? */
>  }
>  #endif /* APR_HAS_MMAP */
> -
> -typedef struct {
> -    char *buf;
> -    char *cur;
> -    apr_size_t avail;
> -} old_write_filter_ctx;
> -
> -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter(
> -    ap_filter_t *f, apr_bucket_brigade *bb)
> -{
> -    old_write_filter_ctx *ctx = f->ctx;
> -
> -    AP_DEBUG_ASSERT(ctx);
> -
> -    if (ctx->buf != NULL) {
> -        apr_size_t nbyte = ctx->cur - ctx->buf;
> -
> -        if (nbyte != 0) {
> -            /* whatever is coming down the pipe (we don't care), we
> -               can simply insert our buffered data at the front and
> -               pass the whole bundle down the chain. */
> -            apr_bucket *b = apr_bucket_create_heap(ctx->buf, nbyte, 0, NULL);
> -            APR_BRIGADE_INSERT_HEAD(bb, b);
> -            ctx->buf = NULL;
> -        }
> -    }
> -
> -    return ap_pass_brigade(f->next, bb);
> -}
> -
> -static apr_status_t flush_buffer(request_rec *r, old_write_filter_ctx *ctx,
> -                                 const char *extra, apr_size_t extra_len)
> -{
> -    apr_bucket_brigade *bb = apr_brigade_create(r->pool);
> -    apr_size_t nbyte = ctx->cur - ctx->buf;
> -    apr_bucket *b = apr_bucket_create_heap(ctx->buf, nbyte, 0, NULL);
> -
> -    APR_BRIGADE_INSERT_TAIL(bb, b);
> -    ctx->buf = NULL;
> -
> -    /* if there is extra data, then send that, too */
> -    if (extra != NULL) {
> -        b = apr_bucket_create_transient(extra, extra_len);
> -        APR_BRIGADE_INSERT_TAIL(bb, b);
> -    }
> -
> -    return ap_pass_brigade(r->output_filters, bb);
> -}
> -
> -static apr_status_t buffer_output(request_rec *r,
> -                                  const char *str, apr_size_t len)
> -{
> -    ap_filter_t *f;
> -    old_write_filter_ctx *ctx;
> -    apr_size_t amt;
> -    apr_status_t status;
> -
> -    if (len == 0)
> -        return APR_SUCCESS;
> -
> -    /* ### future optimization: record some flags in the request_rec to
> -       ### say whether we've added our filter, and whether it is first. */
> -
> -    /* this will typically exit on the first test */
> -    for (f = r->output_filters; f != NULL; f = f->next)
> -        if (strcmp("OLD_WRITE", f->frec->name) == 0)
> -            break;
> -    if (f == NULL) {
> -        /* our filter hasn't been added yet */
> -        ctx = apr_pcalloc(r->pool, sizeof(*ctx));
> -        ap_add_output_filter("OLD_WRITE", ctx, r, r->connection);
> -    }
> -
> -    /* if the first filter is not our buffering filter, then we have to
> -       deliver the content through the normal filter chain */
> -    if (strcmp("OLD_WRITE", r->output_filters->frec->name) != 0) {
> -        apr_bucket_brigade *bb = apr_brigade_create(r->pool);
> -        apr_bucket *b = apr_bucket_create_transient(str, len);
> -        APR_BRIGADE_INSERT_TAIL(bb, b);
> -
> -        return ap_pass_brigade(r->output_filters, bb);
> -    }
> -
> -    /* grab the context from our filter */
> -    ctx = r->output_filters->ctx;
> -
> -    /* if there isn't a buffer in the context yet, put one there. */
> -    if (ctx->buf == NULL) {
> -        /* use the heap so it will get free'd after being flushed */
> -        ctx->avail = AP_MIN_BYTES_TO_WRITE;
> -        ctx->buf = ctx->cur = malloc(ctx->avail);
> -    }
> -
> -    /* squeeze the data into the existing buffer */
> -    if (len <= ctx->avail) {
> -        memcpy(ctx->cur, str, len);
> -        ctx->cur += len;
> -        if ((ctx->avail -= len) == 0)
> -            return flush_buffer(r, ctx, NULL, 0);
> -        return APR_SUCCESS;
> -    }
> -
> -    /* the new content can't fit in the existing buffer */
> -
> -    if (len >= AP_MIN_BYTES_TO_WRITE) {
> -        /* it is really big. send what we have, and the new stuff. */
> -        return flush_buffer(r, ctx, str, len);
> -    }
> -
> -    /* the new data is small. put some into the current buffer, flush it,
> -       and then drop the remaining into a new buffer. */
> -    amt = ctx->avail;
> -    memcpy(ctx->cur, str, amt);
> -    ctx->cur += amt;
> -    ctx->avail = 0;
> -    if ((status = flush_buffer(r, ctx, NULL, 0)) != APR_SUCCESS)
> -        return status;
> -
> -    ctx->buf = malloc(AP_MIN_BYTES_TO_WRITE);
> -    memcpy(ctx->buf, str + amt, len - amt);
> -    ctx->cur = ctx->buf + (len - amt);
> -    ctx->avail = AP_MIN_BYTES_TO_WRITE - (len - amt);
> -
> -    return APR_SUCCESS;
> -}
> -
> -AP_DECLARE(int) ap_rputc(int c, request_rec *r)
> -{
> -    char c2 = (char)c;
> -
> -    if (r->connection->aborted) {
> -	return -1;
> -    }
> -
> -    if (buffer_output(r, &c2, 1) != APR_SUCCESS)
> -        return -1;
> -
> -    return c;
> -}
> -
> -AP_DECLARE(int) ap_rputs(const char *str, request_rec *r)
> -{
> -    apr_size_t len;
> -
> -    if (r->connection->aborted)
> -        return -1;
> -
> -    if (buffer_output(r, str, len = strlen(str)) != APR_SUCCESS)
> -        return -1;
> -
> -    return len;
> -}
> -
> -AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
> -{
> -    if (r->connection->aborted)
> -        return -1;
> -
> -    if (buffer_output(r, buf, nbyte) != APR_SUCCESS)
> -        return -1;
> -
> -    return nbyte;
> -}
> -
> -AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
> -{
> -    char buf[4096];
> -    apr_size_t written;
> -
> -    if (r->connection->aborted)
> -        return -1;
> -
> -    /* ### fix this mechanism to allow more than 4K of output */
> -    written = apr_vsnprintf(buf, sizeof(buf), fmt, va);
> -    if (buffer_output(r, buf, written) != APR_SUCCESS)
> -        return -1;
> -
> -    return written;
> -}
> -
> -AP_DECLARE_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
> -{
> -    va_list va;
> -    int n;
> -
> -    if (r->connection->aborted)
> -        return -1;
> -
> -    va_start(va, fmt);
> -    n = ap_vrprintf(r, fmt, va);
> -    va_end(va);
> -
> -    return n;
> -}
> -
> -AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r, ...)
> -{
> -    va_list va;
> -    const char *s;
> -    apr_size_t len;
> -    apr_size_t written = 0;
> -
> -    if (r->connection->aborted)
> -        return -1;
> -
> -    /* ### TODO: if the total output is large, put all the strings
> -       ### into a single brigade, rather than flushing each time we
> -       ### fill the buffer */
> -    va_start(va, r);
> -    while (1) {
> -        s = va_arg(va, const char *);
> -        if (s == NULL)
> -            break;
> -
> -        len = strlen(s);
> -        if (buffer_output(r, s, len) != APR_SUCCESS) {
> -            return -1;
> -        }
> -
> -        written += len;
> -    }
> -    va_end(va);
> -
> -    return written;
> -}
> -
> -AP_DECLARE(int) ap_rflush(request_rec *r)
> -{
> -    apr_bucket_brigade *bb;
> -    apr_bucket *b;
> -
> -    bb = apr_brigade_create(r->pool);
> -    b = apr_bucket_create_flush();
> -    APR_BRIGADE_INSERT_TAIL(bb, b);
> -    if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS)
> -        return -1;
> -    return 0;
> -}
>  
>  static const char *add_optional_notes(request_rec *r, 
>                                        const char *prefix,
> Index: server/util_filter.c
> ===================================================================
> RCS file: /home/cvs/httpd-2.0/server/util_filter.c,v
> retrieving revision 1.43
> diff -u -d -b -w -u -r1.43 util_filter.c
> --- server/util_filter.c	2001/01/19 07:04:29	1.43
> +++ server/util_filter.c	2001/02/06 05:19:44
> @@ -265,3 +265,74 @@
>      APR_BRIGADE_CONCAT(*saveto, *b);
>      return APR_SUCCESS;
>  }
> +
> +static apr_status_t brigade_flush(apr_bucket_brigade *bb, void *ctx)
> +{
> +    ap_filter_t *f = ctx;
> +
> +    return ap_pass_brigade(f, bb);
> +}
> +
> +AP_DECLARE(apr_status_t) ap_fwrite(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                   const char *str, apr_size_t nbyte)
> +{
> +    apr_bucket *b;
> +    apr_status_t status;
> +
> +    if (nbyte == 0)
> +        return 0;
> +
> +    b = APR_BRIGADE_LAST(bb);
> +
> +    bb->flush = brigade_flush;
> +    bb->ctx = f->next;
> +    status = apr_brigade_write(bb, str, nbyte);
> +
> +    /* We are just checking to see if we just converted the
> +     * buffer into a new bucket and put it at the end of the brigade.  If
> +     * we did, we want to pass the brigade to the next filter.  If not,
> +     * we just keep going.  This allows us to use the network to limit how
> +     * much data we send at any one time.
> +     */
> +    if (b != APR_BRIGADE_LAST(bb)) {
> +        ap_pass_brigade(f->next, bb);
> +    }
> +    return status;
> +}
> +
> +AP_DECLARE(apr_status_t) ap_fputs(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                  const char *str)
> +{
> +    int j = strlen(str);
> +
> +    return ap_fwrite(f, bb, str, j);
> +}
> +
> +AP_DECLARE(apr_status_t) ap_fputc(ap_filter_t *f, apr_bucket_brigade *bb,
> +                                  char str)
> +{
> +    return ap_fwrite(f, bb, &str, 1);
> +}
> +
> +AP_DECLARE(apr_status_t) ap_fvputs(ap_filter_t *f, apr_bucket_brigade *bb, ...)
> +{
> +    apr_size_t written;
> +    va_list va;
> +
> +    va_start(va, bb);
> +    written = apr_brigade_vputstrs(bb, va);
> +    va_end(va);
> +    return written;
> +}
> +
> +AP_DECLARE(apr_status_t) ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char
*fmt, ...)
> +{
> +
> +    apr_size_t written;
> +    va_list va;
> +
> +    va_start(va, fmt);
> +    written = apr_brigade_vprintf(bb, fmt, va);
> +    va_end(va);
> +    return written;
> +}
> Index: srclib/apr-util/buckets/apr_brigade.c
> ===================================================================
> RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v
> retrieving revision 1.3
> diff -u -d -b -w -u -r1.3 apr_brigade.c
> --- srclib/apr-util/buckets/apr_brigade.c	2001/01/19 07:01:59	1.3
> +++ srclib/apr-util/buckets/apr_brigade.c	2001/02/06 05:20:12
> @@ -56,6 +56,7 @@
>  #include "apr_lib.h"
>  #include "apr_pools.h"
>  #include "apr_tables.h"
> +#include "apr_buckets.h"
>  #include "apr_errno.h"
>  
>  #include <stdlib.h>
> @@ -66,8 +67,6 @@
>  #include <sys/uio.h>
>  #endif
>  
> -#include "apr_buckets.h"
> -
>  static apr_status_t apr_brigade_cleanup(void *data)
>  {
>      apr_bucket_brigade *b = data;
> @@ -97,8 +96,9 @@
>  {
>      apr_bucket_brigade *b;
>  
> -    b = apr_palloc(p, sizeof(*b));
> +    b = apr_pcalloc(p, sizeof(*b));
>      b->p = p;
> +
>      APR_RING_INIT(&b->list, apr_bucket, link);
>  
>      apr_register_cleanup(b->p, b, apr_brigade_cleanup, apr_brigade_cleanup);
> @@ -185,12 +185,45 @@
>      return vec - orig;
>  }
>  
> +static int check_brigade_flush(const char **str, 
> +                               apr_size_t *n, apr_bucket_brigade *bb)
> +{
> +    apr_bucket *b = APR_BRIGADE_LAST(bb);
> +
> +    if (APR_BRIGADE_EMPTY(bb)) {
> +        if (*n > APR_BUCKET_BUFF_SIZE) {
> +            apr_bucket *e = apr_bucket_create_transient(*str, *n);
> +            APR_BRIGADE_INSERT_TAIL(bb, e);
> +            return 1;
> +        }
> +        else {
> +            return 0;
> +        }
> +    }
> +
> +    if (APR_BUCKET_IS_HEAP(b)) {
> +        apr_bucket_shared *s = b->data;
> +        apr_bucket_heap *h = s->data;
> +
> +        if (*n > (h->alloc_len - (s->end - s->start))) {
> +            apr_bucket *e = apr_bucket_create_transient(*str, *n);
> +            APR_BRIGADE_INSERT_TAIL(bb, e);
> +            return 1;
> +        }
> +    }
> +    else if (*n > APR_BUCKET_BUFF_SIZE) {
> +        apr_bucket *e = apr_bucket_create_transient(*str, *n);
> +        APR_BRIGADE_INSERT_TAIL(bb, e);
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
>  APU_DECLARE(int) apr_brigade_vputstrs(apr_bucket_brigade *b, va_list va)
>  {
> -    apr_bucket *r;
>      const char *x;
>      int j, k;
> -    apr_size_t i;
>  
>      for (k = 0;;) {
>          x = va_arg(va, const char *);
> @@ -198,20 +231,91 @@
>              break;
>          j = strlen(x);
>         
> -	/* XXX: copy or not? let the caller decide? */
> -        r = apr_bucket_create_heap(x, j, 1, &i);
> -        if (i != j) {
> -            /* Do we need better error reporting?  */
> -            return -1;
> +        k += apr_brigade_write(b, x, j);
>          }
> -        k += i;
> +    return k;
> +}
>  
> -        APR_BRIGADE_INSERT_TAIL(b, r);
> +APU_DECLARE(int) apr_brigade_putc(apr_bucket_brigade *b, const char c)
> +{
> +    apr_size_t nbyte = 1;
> +    const char *str = &c;
> +
> +    if (check_brigade_flush(&str, &nbyte, b)) {
> +        if (b->flush) {
> +            return b->flush(b, b->ctx);
> +        }
>      }
> +    else {
> +        apr_bucket *buck = APR_BRIGADE_LAST(b);
> +        apr_bucket_shared *s;
> +        apr_bucket_heap *h;
> +        char *buf;
>  
> -    return k;
> +        if (!APR_BUCKET_IS_HEAP(buck) || APR_BRIGADE_EMPTY(b)) {
> +            buf = malloc(APR_BUCKET_BUFF_SIZE);
> +
> +            buck = apr_bucket_create_heap(buf, APR_BUCKET_BUFF_SIZE, 0, NULL);
> +            s = buck->data;
> +            s->start = s->end = 0;
> +            h = s->data;
> +
> +            APR_BRIGADE_INSERT_TAIL(b, buck);
> +        }
> +        else {
> +            buf = h->base + s->end;
> +
> +            s = buck->data;
> +            h = s->data;
> +        }
> +        memcpy(buf, &c, 1);
> +        s->end++;
> +    }
> +
> +    return 1;
> +}
> +
> +APU_DECLARE(int) apr_brigade_write(apr_bucket_brigade *b, const char *str, apr_size_t
nbyte)
> +{
> +    if (check_brigade_flush(&str, &nbyte, b)) {
> +        if (b->flush) {
> +            return b->flush(b, b->ctx);
> +        }
> +    }
> +    else {
> +        apr_bucket *buck = APR_BRIGADE_LAST(b);
> +        apr_bucket_shared *s;
> +        apr_bucket_heap *h;
> +        char *buf;
> +
> +        if (!APR_BUCKET_IS_HEAP(buck) || APR_BRIGADE_EMPTY(b)) {
> +            buf = malloc(APR_BUCKET_BUFF_SIZE);
> +
> +            buck = apr_bucket_create_heap(buf, APR_BUCKET_BUFF_SIZE, 0, NULL);
> +            s = buck->data;
> +            s->start = s->end = 0;
> +            h = s->data;
> +
> +            APR_BRIGADE_INSERT_TAIL(b, buck);
> +        }
> +        else {
> +            s = buck->data;
> +            h = s->data;
> +
> +            buf = h->base + s->end;
>  }
>  
> +        memcpy(buf, str, nbyte);
> +        s->end += nbyte;
> +    }
> +    return nbyte;
> +}
> +
> +APU_DECLARE(int) apr_brigade_puts(apr_bucket_brigade *b, const char *str)
> +{
> +    return apr_brigade_write(b, str, strlen(str));
> +}
> +
>  APU_DECLARE_NONSTD(int) apr_brigade_putstrs(apr_bucket_brigade *b, ...)
>  {
>      va_list va;
> @@ -240,13 +344,9 @@
>       * directly into a bucket.  I'm being lazy right now.  RBB
>       */
>      char buf[4096];
> -    apr_bucket *r;
> -    int res;
>  
> -    res = apr_vsnprintf(buf, 4096, fmt, va);
> -
> -    r = apr_bucket_create_heap(buf, strlen(buf), 1, NULL);
> -    APR_BRIGADE_INSERT_TAIL(b, r);
> +    apr_vsnprintf(buf, 4096, fmt, va);
>  
> -    return res;
> +    return apr_brigade_puts(b, buf);
>  }
> +
> Index: srclib/apr-util/include/apr_buckets.h
> ===================================================================
> RCS file: /home/cvs/apr-util/include/apr_buckets.h,v
> retrieving revision 1.68
> diff -u -d -b -w -u -r1.68 apr_buckets.h
> --- srclib/apr-util/include/apr_buckets.h	2001/01/27 14:52:55	1.68
> +++ srclib/apr-util/include/apr_buckets.h	2001/02/06 05:20:14
> @@ -78,6 +78,8 @@
>   * @package Bucket Brigades
>   */
>  
> +#define APR_BUCKET_BUFF_SIZE 9000
> +
>  typedef enum {APR_BLOCK_READ, APR_NONBLOCK_READ} apr_read_type_e;
>  
>  /*
> @@ -237,6 +239,8 @@
>       *  the destroying function is responsible for killing the cleanup.
>       */
>      apr_pool_t *p;
> +    void *ctx;
> +    apr_status_t (*flush)(apr_bucket_brigade *bb, void *ctx);
>      /** The buckets in the brigade are on this list. */
>      /*
>       * XXX: the apr_bucket_list structure doesn't actually need a name tag
> @@ -533,7 +537,7 @@
>       * modified, it is only used to free the bucket.
>       */
>      char    *base;
> -    /** how much memory was allocated.  This may not be necessary */
> +    /** how much memory was allocated */
>      size_t  alloc_len;
>  };
>  
> @@ -629,8 +633,7 @@
>  				     struct iovec *vec, int nvec);
>  
>  /**
> - * This function writes a list of strings into a bucket brigade.  We just 
> - * allocate a new heap bucket for each string.
> + * This function writes a list of strings into a bucket brigade. 
>   * @param b The bucket brigade to add to
>   * @param va A list of strings to add
>   * @return The number of bytes added to the brigade
> @@ -639,8 +642,34 @@
>  APU_DECLARE(int) apr_brigade_vputstrs(apr_bucket_brigade *b, va_list va);
>  
>  /**
> + * This function writes an string into a bucket brigade.
> + * @param b The bucket brigade to add to
> + * @param str The string to add
> + * @return The number of bytes added to the brigade
> + * @deffunc int apr_brigade_write(ap_bucket_brigade *b, const char *str)
> + */
> +APU_DECLARE(int) apr_brigade_write(apr_bucket_brigade *b, const char *str, apr_size_t
nbyte);
> +
> +/**
> + * This function writes an string into a bucket brigade.
> + * @param b The bucket brigade to add to
> + * @param str The string to add
> + * @return The number of bytes added to the brigade
> + * @deffunc int apr_brigade_puts(ap_bucket_brigade *b, const char *str)
> + */
> +APU_DECLARE(int) apr_brigade_puts(apr_bucket_brigade *b, const char *str);
> +
> +/**
> + * This function writes a character into a bucket brigade.
> + * @param b The bucket brigade to add to
> + * @param c The character to add
> + * @return The number of bytes added to the brigade
> + * @deffunc int apr_brigade_putc(apr_bucket_brigade *b, const char c)
> + */
> +APU_DECLARE(int) apr_brigade_putc(apr_bucket_brigade *b, const char c);
> +
> +/**
>   * This function writes an unspecified number of strings into a bucket brigade.
> - * We just allocate a new heap bucket for each string.
>   * @param b The bucket brigade to add to
>   * @param ... The strings to add
>   * @return The number of bytes added to the brigade
> @@ -649,7 +678,7 @@
>  APU_DECLARE_NONSTD(int) apr_brigade_putstrs(apr_bucket_brigade *b, ...);
>  
>  /**
> - * Evaluate a printf and put the resulting string into a bucket at the end 
> + * Evaluate a printf and put the resulting string at the end 
>   * of the bucket brigade.
>   * @param b The brigade to write to
>   * @param fmt The format of the string to write
> @@ -661,7 +690,7 @@
>                                            const char *fmt, ...);
>  
>  /**
> - * Evaluate a printf and put the resulting string into a bucket at the end 
> + * Evaluate a printf and put the resulting string at the end 
>   * of the bucket brigade.
>   * @param b The brigade to write to
>   * @param fmt The format of the string to write
> 
> 
> _______________________________________________________________________________
> Ryan Bloom                        	rbb@apache.org
> 406 29th St.
> San Francisco, CA 94131
> -------------------------------------------------------------------------------
> 
> 


_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Mime
View raw message