httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Greg Stein <gst...@lyra.org>
Subject Re: Filter I/O take 3.
Date Fri, 16 Jun 2000 14:27:34 GMT
At the moment, Apache is a "push" model, from the original content source,
down to the network layer. That is pretty ingrained into Apache's
architecture. I presume for an async I/O approach, you would need to flip
this around where the network layer says "I'm ready for more" and "pulls"
content. Is my read on the situation correct?

If so, then I will venture a guess that we aren't going to be able to get
Apache to an async model because of that ingrained "push" model.

Cheers,
-g

On Fri, Jun 16, 2000 at 09:59:16AM -0400, Bill Stoddard wrote:
> I haven't been following the debate closely so I may not understand all the details here,
> but I have a concern...
> 
> I strongly believe that making Apache do async network I/O is very important. It allows us
> to do the work of 1000's blocking threads with just a few threads. Will this patch make it
> substantially more difficult to cleanely implement async network i/o? I fear it does (with
> all the talk of allocating storage out of the stack, etc.)
> 
> Bill
> 
> ----- Original Message -----
> From: <rbb@covalent.net>
> To: <new-httpd@apache.org>
> Sent: Thursday, June 15, 2000 6:52 PM
> Subject: Filter I/O take 3.
> 
> 
> >
> > This patch enable filtering output.  I have not implemented input
> > filtering, because I believe it is trivial once we have the output
> > done.
> >
> > Issues resolved:
> >      Grouping filters by type
> >      allocating space on the stack or heap as appropriate
> >      memcpy'ing data that is never modified (not done anymore)
> >      Send headers after filters have sent the first block of data.
> >
> > Issues not resolved:
> >      Negative pushback from the network (there is a comment in the code
> > for how to implement this)
> >      Filters that only deal with half the data.  (the basic idea is there,
> > but it is not well tested.  Still working on this).
> >      cleanup the code:  some stuff just commented out until it can be
> > tested better.
> >      insert ap_run_insert_filters for sub_requests???  I'm not sure about
> > this.  Maybe we just want to inherit these.
> >      Others?  I know there are others, but I can't think of them right
> > now.
> >
> >
> > Patch
> > _____
> >
> > Index: src/include/ap_hooks.h
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/include/ap_hooks.h,v
> > retrieving revision 1.20
> > diff -u -d -b -w -u -r1.20 ap_hooks.h
> > --- src/include/ap_hooks.h 2000/05/27 22:53:46 1.20
> > +++ src/include/ap_hooks.h 2000/06/15 22:43:33
> > @@ -167,12 +167,153 @@
> >      return decline; \
> >      }
> >
> > +/* Set of Hook definitions designed to put the list of functions off a
> > + * pointer pre-defined in the request_rec.
> > + */
> > +#define AP_DECLARE_RHOOK(ret,name,args) \
> > +typedef ret HOOK_##name args; \
> > +API_EXPORT(void) ap_rhook_##name(HOOK_##name *pf,request_rec *r, \
> > +                                 const char * const *aszPre,\
> > +                  const char * const *aszSucc,int nOrder); \
> > +API_EXPORT(ret) ap_run_##name args; \
> > +typedef struct _LINK_##name \
> > +    { \
> > +    HOOK_##name *pFunc; \
> > +    const char *szName; \
> > +    const char * const *aszPredecessors; \
> > +    const char * const *aszSuccessors; \
> > +    int nOrder; \
> > +    } LINK_##name;
> > +
> > +#define AP_RHOOK_STRUCT(members) \
> > +struct { members } _hooks;
> > +
> > +#define AP_RHOOK_LINK(name) \
> > +    ap_array_header_t *link_##name;
> > +
> > +#define AP_IMPLEMENT_RHOOK_BASE(name) \
> > +API_EXPORT(void) ap_rhook_##name(HOOK_##name *pf,request_rec *r, \
> > +                                 const char * const *aszPre,\
> > +                  const char * const *aszSucc,int nOrder) \
> > +    { \
> > +    LINK_##name *pHook; \
> > +    if(!r->_hooks.link_##name) \
> > + { \
> > + r->_hooks.link_##name=ap_make_array(r->pool,1,sizeof(LINK_##name)); \
> > + ap_hook_sort_register(#name,&r->_hooks.link_##name); \
> > + } \
> > +    pHook=ap_push_array(r->_hooks.link_##name); \
> > +    pHook->pFunc=pf; \
> > +    pHook->aszPredecessors=aszPre; \
> > +    pHook->aszSuccessors=aszSucc; \
> > +    pHook->nOrder=nOrder; \
> > +    pHook->szName=ap_debug_module_name; \
> > +    if(ap_debug_module_hooks) \
> > + ap_show_hook(#name,aszPre,aszSucc); \
> > +    }
> > +
> > +/* RUN_ALL runs to the first one to return other than ok or decline
> > +   RUN_FIRST runs to the first one to return other than decline
> > +   VOID runs all
> > +*/
> > +
> > +#define AP_IMPLEMENT_RHOOK_VOID(name,args_decl,args_use) \
> > +AP_IMPLEMENT_RHOOK_BASE(name) \
> > +API_EXPORT(void) ap_run_##name args_decl \
> > +    { \
> > +    LINK_##name *pHook; \
> > +    int n; \
> > +\
> > +    if(!r->_hooks.link_##name) \
> > + return; \
> > +\
> > +    pHook=(LINK_##name *)r->_hooks.link_##name->elts; \
> > +    for(n=0 ; n < r->_hooks.link_##name->nelts ; ++n) \
> > + pHook[n].pFunc args_use; \
> > +    }
> > +
> > +/* FIXME: note that this returns ok when nothing is run. I suspect it should
> > +   really return decline, but that breaks Apache currently - Ben
> > +*/
> > +#define AP_IMPLEMENT_RHOOK_RUN_ALL(ret,name,args_decl,args_use,ok,decline) \
> > +AP_IMPLEMENT_RHOOK_BASE(name) \
> > +API_EXPORT(ret) ap_run_##name args_decl \
> > +    { \
> > +    LINK_##name *pHook; \
> > +    int n; \
> > +    ret rv; \
> > +\
> > +    if(!r->_hooks.link_##name) \
> > + return ok; \
> > +\
> > +    pHook=(LINK_##name *)r->_hooks.link_##name->elts; \
> > +    for(n=0 ; n < r->_hooks.link_##name->nelts ; ++n) \
> > + { \
> > + rv=pHook[n].pFunc args_use; \
> > +\
> > + if(rv != ok && rv != decline) \
> > +     return rv; \
> > + } \
> > +    return ok; \
> > +    }
> > +
> > +#define AP_IMPLEMENT_RHOOK_RUN_FIRST(ret,name,args_decl,args_use,decline) \
> > +AP_IMPLEMENT_RHOOK_BASE(name) \
> > +API_EXPORT(ret) ap_run_##name args_decl \
> > +    { \
> > +    LINK_##name *pHook; \
> > +    int n; \
> > +    ret rv; \
> > +\
> > +    if(!r->_hooks.link_##name) \
> > + return decline; \
> > +\
> > +    pHook=(LINK_##name *)r->_hooks.link_##name->elts; \
> > +    for(n=0 ; n < r->_hooks.link_##name->nelts ; ++n) \
> > + { \
> > + rv=pHook[n].pFunc args_use; \
> > +\
> > + if(rv != decline) \
> > +     return rv; \
> > + } \
> > +    return decline; \
> > +    }
> > +
> >       /* Hook orderings */
> >  #define AP_HOOK_REALLY_FIRST (-10)
> >  #define AP_HOOK_FIRST 0
> >  #define AP_HOOK_MIDDLE 10
> >  #define AP_HOOK_LAST 20
> >  #define AP_HOOK_REALLY_LAST 30
> > +
> > +/* I'm not sure if this is the right place for this or not, but it's a good
> > + * starting point.  This is the filter hooks ordering definitions.
> > + * The five classes are:
> > + *
> > + *    content-generators:
> > + *        These are ignored here, because all generators are implemented
> > + *        using handlers.
> > + *    content-filter/munger/processor:
> > + *        These are things like SSI, PHP, etc.  Anything that is likely
> > + *        to change the meaning of the data being sent.
> > + *    content-encoding:
> > + *        Something like gzip would go here.  Anything that changes the data,
> > + *        but not the meaning.
> > + *    digest/message processor:
> > + *        This would be something like mod_auth_digest.  Anything that
> > + *        changes header fields but not the content.
> > + *    transport encoding:
> > + *        This is where chuncking, SSL belong.  Anything that modifies the
> > + *        message for reasons related to the transport layer, but doesn't
> > + *        modify the meaning of the body.
> > + *
> > + * These filter types are called in the order the are listed above.
> > + */
> > +
> > +#define AP_HOOK_FILTER          0      /* content-filter/munger/processor */
> > +#define AP_HOOK_ENCODING       10      /* content-encoding */
> > +#define AP_HOOK_PROCESSOR      20      /* digest/message processor */
> > +#define AP_HOOK_TRANSPORT      30      /* transport-encoding */
> >
> >  extern API_VAR_EXPORT ap_pool_t *ap_global_hook_pool;
> >  extern API_VAR_EXPORT int ap_debug_module_hooks;
> > Index: src/include/http_request.h
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/include/http_request.h,v
> > retrieving revision 1.11
> > diff -u -d -b -w -u -r1.11 http_request.h
> > --- src/include/http_request.h 2000/05/27 22:53:47 1.11
> > +++ src/include/http_request.h 2000/06/15 22:43:34
> > @@ -120,6 +120,7 @@
> >  AP_DECLARE_HOOK(int,type_checker,(request_rec *))
> >  AP_DECLARE_HOOK(int,access_checker,(request_rec *))
> >  AP_DECLARE_HOOK(int,auth_checker,(request_rec *))
> > +AP_DECLARE_HOOK(void,insert_filter,(request_rec *))
> >
> >  #ifdef __cplusplus
> >  }
> > Index: src/include/httpd.h
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
> > retrieving revision 1.56
> > diff -u -d -b -w -u -r1.56 httpd.h
> > --- src/include/httpd.h 2000/06/09 21:19:47 1.56
> > +++ src/include/httpd.h 2000/06/15 22:43:44
> > @@ -81,6 +81,8 @@
> >  #include "apr_network_io.h"
> >  #include "buff.h"
> >  #include "ap_mmn.h"
> > +#include "ap_hooks.h"
> > +#include "ap_ioblock.h"
> >
> >  #ifdef HAVE_NETINET_IN_H
> >  #include <netinet/in.h>
> > @@ -598,6 +600,8 @@
> >      const char *short_name;
> >  };
> >
> > +AP_DECLARE_RHOOK(ap_ioqueue_t *, filter, (request_rec *r, ap_ioqueue_t *strs));
> > +
> >  struct request_rec {
> >
> >      ap_pool_t *pool;
> > @@ -615,6 +619,12 @@
> >   * pointer back to the main request.
> >   */
> >
> > +    AP_RHOOK_STRUCT (
> > +        AP_RHOOK_LINK(filter)   /* per-request filter I/O hook. */
> > +    );
> > +    ap_ioqueue_t **unfiltered_data; /* array of (ap_ioqueue_t *) that has
> > +                                         * not been filtered for */
> > +
> >      /* Info about the request itself... we begin with stuff that only
> >       * protocol.c should ever touch...
> >       */
> > @@ -662,6 +672,7 @@
> >      */
> >      int allowed; /* Allowed methods - for 405, OPTIONS, etc */
> >
> > +    int headers_sent;           /* have the headers been sent yet or not */
> >      int sent_bodyct; /* byte count in stream is for body */
> >      long bytes_sent; /* body byte count, for easy access */
> >      ap_time_t mtime; /* Time the resource was last modified */
> > Index: src/main/Makefile.in
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/main/Makefile.in,v
> > retrieving revision 1.12
> > diff -u -d -b -w -u -r1.12 Makefile.in
> > --- src/main/Makefile.in 2000/06/11 11:20:58 1.12
> > +++ src/main/Makefile.in 2000/06/15 22:43:50
> > @@ -8,7 +8,7 @@
> >   http_protocol.c http_request.c http_vhost.c util.c util_date.c \
> >   util_script.c util_uri.c util_md5.c util_cfgtree.c util_ebcdic.c \
> >   rfc1413.c http_connection.c iol_file.c listen.c mpm_common.c \
> > - util_charset.c
> > + util_charset.c ap_ioblock.c
> >
> >  include $(top_srcdir)/build/ltlib.mk
> >
> > Index: src/main/http_core.c
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
> > retrieving revision 1.74
> > diff -u -d -b -w -u -r1.74 http_core.c
> > --- src/main/http_core.c 2000/06/15 13:42:01 1.74
> > +++ src/main/http_core.c 2000/06/15 22:43:54
> > @@ -2628,8 +2628,8 @@
> >
> >   rangestatus = ap_set_byterange(r);
> >
> > - ap_send_http_header(r);
> > -
> > +/* ap_send_http_header(r);
> > +*/
> >   if (!r->header_only) {
> >       if (!rangestatus) {
> >   ap_send_fd(fd, r);
> > @@ -2671,8 +2671,8 @@
> >   }
> >
> >   rangestatus = ap_set_byterange(r);
> > - ap_send_http_header(r);
> > -
> > + /*ap_send_http_header(r);
> > + */
> >   if (!r->header_only) {
> >       if (!rangestatus) {
> >   ap_send_mmap(mm, r, 0, r->finfo.size);
> > Index: src/main/http_protocol.c
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
> > retrieving revision 1.79
> > diff -u -d -b -w -u -r1.79 http_protocol.c
> > --- src/main/http_protocol.c 2000/06/12 23:02:49 1.79
> > +++ src/main/http_protocol.c 2000/06/15 22:44:05
> > @@ -96,6 +96,86 @@
> >            ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
> >    } while (0)
> >
> > +static int filter_io(request_rec *r, ap_ioqueue_t *iov)
> > +{
> > +    ap_ioblock_t *dptr = iov->head;
> > +    ap_ioqueue_t *unfiltered;
> > +#if 0
> > +    /* see below */
> > +    ap_size_t totlen = 0;
> > +#endif
> > +    int i, n;
> > +    int totsent = 0;
> > +    int rv;
> > +    int num_filters = r->_hooks.link_filter->nelts;
> > +
> > +    /* This should probably be done someplace else, but this will work for now.
> > +     */
> > +    if (r->unfiltered_data == NULL) {
> > +        r->unfiltered_data = ap_pcalloc(r->pool, num_filters *
> > +                                           sizeof(ap_ioqueue_t *));
> > +    }
> > +
> > +    for (i = 0; i < r->_hooks.link_filter->nelts; ++i) {
> > +        LINK_filter *hook;
> > +#if 0
> > +    /* Limit the amount of data sent to filters.  This logic needs to ensure
> > +     * we don't send too little or too much information.  I expect this will
> > +     * be added in the not too distant future.  Like days after the original
> > +     * filtered I/O patch.   rbb
> > +     */
> > +        while (dptr != iov->tail && (totlen < MAX_STRING_LEN)) {
> > +            totlen += dptr->len;
> > +            dptr = dptr->next;
> > +        }
> > +#endif
> > +
> > +        if (r->unfiltered_data[i] != NULL) {
> > +            ap_ioqueue_merge(r->unfiltered_data[i], iov);
> > +            iov = r->unfiltered_data[i];
> > +            r->unfiltered_data[i] = NULL;
> > +        }
> > +
> > +        hook = (LINK_filter *)r->_hooks.link_filter->elts;
> > +        unfiltered = hook[i].pFunc(r, iov);
> > +
> > +        /* unfiltered is the data that the filter didn't modify for one reason
> > +         * or another.  This has not been tested, but the theory is sound.
> > +         * I'll test this after I send the patch.  I expect to have this fully
> > +         * tested either before the commit or just after.
> > +         */
> > +        if (unfiltered != NULL) {
> > +            r->unfiltered_data[i] = unfiltered;
> > +        }
> > +    }
> > +
> > +    dptr = iov->head;
> > +
> > +    if (r->headers_sent != 1) {
> > +        /* We haven't sent any headers yet.  We had better do that before
> > +         * we try to send the body.
> > +         */
> > +        ap_send_http_header(r);
> > +    }
> > +
> > +    while (dptr != NULL) {
> > +        rv = ap_bwrite(r->connection->client, dptr->vec, dptr->len, &n);
> > +        if (n < 0) {
> > +            if (!r->connection->aborted) {
> > +                ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
> > +                    "client stopped connection before rwrite completed");
> > +                ap_bsetflag(r->connection->client, B_EOUT, 1);
> > +                r->connection->aborted = 1;
> > +            }
> > +            return EOF;
> > +        }
> > +        totsent += n;
> > +        dptr = dptr->next;
> > +    }
> > +    SET_BYTES_SENT(r);
> > +    return totsent;
> > +}
> > +
> >  /*
> >   * Builds the content-type that should be sent to the client from the
> >   * content-type specified.  The following rules are followed:
> > @@ -1394,7 +1474,8 @@
> >  API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
> >      const char *fieldname, const char *fieldval)
> >  {
> > -    return (0 < ap_rvputs(r, fieldname, ": ", fieldval, CRLF, NULL));
> > +    return (0 < ap_bvputs(r->connection->client, fieldname, ": ", fieldval,
> > +                          CRLF, NULL));
> >  }
> >
> >  API_EXPORT(void) ap_basic_http_header(request_rec *r)
> > @@ -1428,7 +1509,7 @@
> >
> >      /* Output the HTTP/1.x Status-Line and the Date and Server fields */
> >
> > -    ap_rvputs(r, protocol, " ", r->status_line, CRLF, NULL);
> > +    ap_bvputs(r->connection->client, protocol, " ", r->status_line, CRLF, NULL);
> >
> >      date = ap_palloc(r->pool, AP_RFC822_DATE_LEN);
> >      ap_rfc822_date(date, r->request_time);
> > @@ -1465,9 +1546,9 @@
> >
> >      ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
> >      if (bs >= 255 && bs <= 257)
> > -        ap_rputs("X-Pad: avoid browser bug" CRLF, r);
> > +        ap_bputs("X-Pad: avoid browser bug" CRLF, r->connection->client);
> >
> > -    ap_rputs(CRLF, r);  /* Send the terminating empty line */
> > +    ap_bputs(CRLF, r->connection->client); /* Send the terminating empty line */
> >  }
> >
> >  /* Build the Allow field-value from the request handler method mask.
> > @@ -1734,6 +1815,10 @@
> >               (void *) r, r->headers_out, NULL);
> >
> >      terminate_header(r);
> > +    /* We have sent the headers once, we don't ever want to try to send them
> > +     * again.
> > +     */
> > +    r->headers_sent = 1;
> >
> >
> >      ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
> > @@ -2216,7 +2301,7 @@
> >          o = 0;
> >
> >          while (n && !ap_is_aborted(r->connection)) {
> > -            rv = ap_bwrite(r->connection->client, &buf[o], n, &w);
> > +            w = ap_rwrite(&buf[o], n, r);
> >              if (w > 0) {
> >                  total_bytes_sent += w;
> >                  n -= w;
> > @@ -2347,13 +2432,11 @@
> >      size_t total_bytes_sent = 0;
> >      int n;
> >      ap_ssize_t w;
> > -    ap_status_t rv;
> >      char *addr;
> >
> >      if (length == 0)
> >          return 0;
> >
> > -
> >      length += offset;
> >      while (!r->connection->aborted && offset < length) {
> >          if (length - offset > MMAP_SEGMENT_SIZE) {
> > @@ -2365,25 +2448,12 @@
> >
> >          while (n && !r->connection->aborted) {
> >              ap_mmap_offset((void**)&addr, mm, offset);
> > -            rv = ap_bwrite(r->connection->client, addr, n, &w);
> > +            w = ap_rwrite(addr, n, r);
> >              if (w > 0) {
> >                  total_bytes_sent += w;
> >                  n -= w;
> >                  offset += w;
> >              }
> > -            else if (rv != APR_SUCCESS) {
> > -                if (r->connection->aborted)
> > -                    break;
> > -                else if (ap_canonical_error(rv) == APR_EAGAIN)
> > -                    continue;
> > -                else {
> > -                    ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
> > -                     "client stopped connection before send mmap completed");
> > -                    ap_bsetflag(r->connection->client, B_EOUT, 1);
> > -                    r->connection->aborted = 1;
> > -                    break;
> > -                }
> > -            }
> >          }
> >      }
> >
> > @@ -2397,6 +2467,8 @@
> >      if (r->connection->aborted)
> >          return EOF;
> >
> > +    filter_io(r, ap_create_ioqueue(r->pool, (const char *)&c, 1));
> > +
> >      if (ap_bputc(c, r->connection->client) < 0) {
> >          if (!r->connection->aborted) {
> >              ap_log_rerror(APLOG_MARK, APLOG_INFO,
> > @@ -2414,10 +2486,14 @@
> >  API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
> >  {
> >      int rcode;
> > +    int len;
> >
> >      if (r->connection->aborted)
> >          return EOF;
> >
> > +    len = strlen(str);
> > +    filter_io(r, ap_create_ioqueue(r->pool, str, len));
> > +
> >      rcode = ap_bputs(str, r->connection->client);
> >      if (rcode < 0) {
> >          if (!r->connection->aborted) {
> > @@ -2435,73 +2511,40 @@
> >
> >  API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
> >  {
> > -    ap_ssize_t n;
> > -    ap_status_t rv;
> > -
> >      if (r->connection->aborted)
> >          return EOF;
> >
> > -    rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
> > -    if (n < 0) {
> > -        if (!r->connection->aborted) {
> > -            ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
> > -                "client stopped connection before rwrite completed");
> > -            ap_bsetflag(r->connection->client, B_EOUT, 1);
> > -            r->connection->aborted = 1;
> > -        }
> > -        return EOF;
> > -    }
> > -    SET_BYTES_SENT(r);
> > -    return n;
> > +    return filter_io(r, ap_create_ioqueue(r->pool, buf, nbyte));
> >  }
> >
> >  API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list ap)
> >  {
> > -    int n;
> > +    int len;
> > +    char *str;
> >
> >      if (r->connection->aborted)
> >          return -1;
> > -
> > -    n = ap_vbprintf(r->connection->client, fmt, ap);
> >
> > -    if (n < 0) {
> > -        if (!r->connection->aborted) {
> > -            ap_log_rerror(APLOG_MARK, APLOG_INFO,
> > -                ap_berror(r->connection->client), r,
> > -                "client stopped connection before vrprintf completed");
> > -            ap_bsetflag(r->connection->client, B_EOUT, 1);
> > -            r->connection->aborted = 1;
> > -        }
> > -        return -1;
> > -    }
> > -    SET_BYTES_SENT(r);
> > -    return n;
> > +    str = ap_pvsprintf(r->pool, fmt, ap);
> > +    len = strlen(str);
> > +    return filter_io(r, ap_create_ioqueue(r->pool, str, len));
> >  }
> >
> >  API_EXPORT(int) ap_rprintf(request_rec *r, const char *fmt,...)
> >  {
> >      va_list vlist;
> >      int n;
> > +    char *str;
> >
> >      if (r->connection->aborted)
> >          return -1;
> >
> >      va_start(vlist, fmt);
> > -    n = ap_vbprintf(r->connection->client, fmt, vlist);
> > +    str = ap_pvsprintf(r->pool, fmt, vlist);
> >      va_end(vlist);
> >
> > -    if (n < 0) {
> > -        if (!r->connection->aborted) {
> > -            ap_log_rerror(APLOG_MARK, APLOG_INFO,
> > -                ap_berror(r->connection->client), r,
> > -                "client stopped connection before rprintf completed");
> > -            ap_bsetflag(r->connection->client, B_EOUT, 1);
> > -            r->connection->aborted = 1;
> > -        }
> > -        return -1;
> > -    }
> > -    SET_BYTES_SENT(r);
> > -    return n;
> > +    n = strlen(str);
> > +    return filter_io(r, ap_create_ioqueue(r->pool, str, n));
> >  }
> >
> >  API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
> > @@ -2510,8 +2553,6 @@
> >      ap_ssize_t i;
> >      int j, k;
> >      const char *x;
> > -    BUFF *fb = r->connection->client;
> > -    ap_status_t rv;
> >
> >      if (r->connection->aborted)
> >          return EOF;
> > @@ -2522,8 +2563,11 @@
> >          if (x == NULL)
> >              break;
> >          j = strlen(x);
> > -        rv = ap_bwrite(fb, x, j, &i);
> > -        if (i != j) {
> > +
> > +        i = filter_io(r, ap_create_ioqueue(r->pool, x, j));
> > +
> > +/* I think this can be removed, but I am leaving this here until I am 100% sure.  rbb
> */
> > +/*        if (i != j) {
> >              va_end(args);
> >              if (!r->connection->aborted) {
> >                  ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r,
> > @@ -2532,7 +2576,7 @@
> >                  r->connection->aborted = 1;
> >              }
> >              return EOF;
> > -        }
> > +        }*/
> >          k += i;
> >      }
> >      va_end(args);
> > @@ -2609,7 +2653,7 @@
> >      }
> >
> >      if (status == HTTP_NO_CONTENT) {
> > -        ap_send_http_header(r);
> > +        /*ap_send_http_header(r);*/
> >          ap_finalize_request_protocol(r);
> >          return;
> >      }
> > @@ -2644,7 +2688,7 @@
> >          if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
> >              ap_table_setn(r->headers_out, "Allow", make_allow(r));
> >
> > -        ap_send_http_header(r);
> > +        /*ap_send_http_header(r);*/
> >
> >          if (r->header_only) {
> >              ap_finalize_request_protocol(r);
> > @@ -2952,3 +2996,4 @@
> >                              (const request_rec *r),(r),NULL)
> >  AP_IMPLEMENT_HOOK_RUN_FIRST(unsigned short,default_port,
> >                              (const request_rec *r),(r),0)
> > +AP_IMPLEMENT_RHOOK_BASE(filter)
> > Index: src/main/http_request.c
> > ===================================================================
> > RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
> > retrieving revision 1.32
> > diff -u -d -b -w -u -r1.32 http_request.c
> > --- src/main/http_request.c 2000/06/12 15:28:53 1.32
> > +++ src/main/http_request.c 2000/06/15 22:44:10
> > @@ -68,6 +68,7 @@
> >
> >  #define CORE_PRIVATE
> >  #include "ap_config.h"
> > +#include "ap_hooks.h"
> >  #include "httpd.h"
> >  #include "http_config.h"
> >  #include "http_request.h"
> > @@ -86,6 +87,7 @@
> >       AP_HOOK_LINK(type_checker)
> >       AP_HOOK_LINK(access_checker)
> >       AP_HOOK_LINK(auth_checker)
> > +     AP_HOOK_LINK(insert_filter)
> >  )
> >
> >  AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
> > @@ -100,6 +102,7 @@
> >                            (request_rec *r),(r),OK,DECLINED)
> >  AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
> >                              (request_rec *r),(r),DECLINED)
> > +AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
> >
> >  /*****************************************************************
> >   *
> > @@ -1246,6 +1249,15 @@
> >          ap_die(access_status, r);
> >          return;
> >      }
> > +
> > +    /* The new insert_filter stage makes sense here IMHO.  We are sure that
> > +     * we are going to run the request now, so we may as well insert filters
> > +     * if any are available.  Since the goal of this phase is to allow all
> > +     * modules to insert a filter if they want to, this filter returns
> > +     * void.  I just can't see any way that this filter can reasonably
> > +     * fail, either your modules inserts something or it doesn't.  rbb
> > +     */
> > +    ap_run_insert_filter(r);
> >
> >      if ((access_status = ap_invoke_handler(r)) != 0) {
> >          ap_die(access_status, r);
> >
> > New files:
> > _________
> >
> >
> > ap_ioblock.c:
> > -------------
> >
> > /* ====================================================================
> >  * The Apache Software License, Version 1.1
> >  *
> >  * Copyright (c) 2000 The Apache Software Foundation.  All rights
> >  * reserved.
> >  *
> >  * Redistribution and use in source and binary forms, with or without
> >  * modification, are permitted provided that the following conditions
> >  * are met:
> >  *
> >  * 1. Redistributions of source code must retain the above copyright
> >  *    notice, this list of conditions and the following disclaimer.
> >  *
> >  * 2. Redistributions in binary form must reproduce the above copyright
> >  *    notice, this list of conditions and the following disclaimer in
> >  *    the documentation and/or other materials provided with the
> >  *    distribution.
> >  *
> >  * 3. The end-user documentation included with the redistribution,
> >  *    if any, must include the following acknowledgment:
> >  *       "This product includes software developed by the
> >  *        Apache Software Foundation (http://www.apache.org/)."
> >  *    Alternately, this acknowledgment may appear in the software itself,
> >  *    if and wherever such third-party acknowledgments normally appear.
> >  *
> >  * 4. The names "Apache" and "Apache Software Foundation" must
> >  *    not be used to endorse or promote products derived from this
> >  *    software without prior written permission. For written
> >  *    permission, please contact apache@apache.org.
> >  *
> >  * 5. Products derived from this software may not be called "Apache",
> >  *    nor may "Apache" appear in their name, without prior written
> >  *    permission of the Apache Software Foundation.
> >  *
> >  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> >  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> >  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> >  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> >  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> >  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> >  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> >  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> >  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> >  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> >  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >  * SUCH DAMAGE.
> >  * ====================================================================
> >  *
> >  * This software consists of voluntary contributions made by many
> >  * individuals on behalf of the Apache Software Foundation.  For more
> >  * information on the Apache Software Foundation, please see
> >  * <http://www.apache.org/>.
> >  *
> >  * This file was originally written by Ryan Bloom for Covalent Technologies
> >  * and gifted exclusively to the The Apache Software Foundation in June 2000.
> >  */
> >
> > #include "ap_ioblock.h"
> >
> > ap_ioblock_t *ap_create_ioblock(ap_pool_t *p, const void *v, int length)
> > {
> >     ap_ioblock_t *vector;
> >
> >     vector = ap_pcalloc(p, sizeof(*vector));
> >     vector->vec = (void *)v;
> >     vector->len = length;
> >     vector->bitmask = AP_NOT_WRITABLE;
> >
> >     return vector;
> > }
> >
> > ap_ioqueue_t *ap_start_ioqueue(ap_ioblock_t *b)
> > {
> >     ap_ioqueue_t *q;
> >
> >     q = ap_pcalloc(b->p, sizeof(*q));
> >     q->p = b->p;
> >     q->head = b;
> >     b->prev = NULL;
> >
> >     while (b->next != NULL) {
> >         b = b->next;
> >     }
> >     q->tail = b;
> >
> >     return q;
> > }
> >
> > ap_ioqueue_t *ap_create_ioqueue(ap_pool_t *p, const void *v, int length)
> > {
> >     ap_ioqueue_t *q;
> >
> >     q = ap_pcalloc(p, sizeof(*q));
> >     q->p = p;
> >     q->head = q->tail = ap_create_ioblock(q->p, v, length);
> >
> >     return q;
> > }
> >
> > ap_status_t ap_split_ioblock(ap_ioblock_t *vec, int offset)
> > {
> >     ap_ioblock_t *vector;
> >
> >     vector = ap_pcalloc(vec->p, sizeof(*vector));
> >     vector->p = vec->p;
> >
> >     vector->len = vec->len - offset;
> >     vec->len = offset;
> >     vector->vec = vec->vec + offset;
> >
> >     vector->next = vec->next;
> >     vector->prev = vec;
> >     vec->next = vector;
> >     vector->bitmask = vec->bitmask;
> >     return APR_SUCCESS;
> > }
> >
> > ap_ioblock_t *ap_add_ioblock(ap_ioblock_t *vec, const void *v, int length,
> >                            int front)
> > {
> >     ap_ioblock_t *vector = ap_create_ioblock(vec->p, v, length);
> >     ap_ioblock_t *dptr = vec;
> >
> >     if (front) {
> >         vector->next = vec;
> >         vec->prev = vector;
> >         return vector;
> >     }
> >     while (dptr->next) {
> >         dptr = dptr->next;
> >     }
> >     dptr->next = vector;
> >     vector->prev = dptr;
> >     return vec;
> > }
> >
> > ap_status_t ap_set_ioblock_writable(ap_ioblock_t *vec)
> > {
> >     if (vec->bitmask == AP_WRITABLE) {
> >         return APR_SUCCESS;
> >     }
> >     if (vec->bitmask == AP_NOT_WRITABLE) {
> >         void *v = ap_palloc(vec->p, vec->len);
> >         memcpy(v, vec->vec, vec->len);
> >         vec->vec = v;
> >         return APR_SUCCESS;
> >     }
> >     else return APR_ENOTIMPL;
> > }
> >
> > ap_ioqueue_t *ap_ioblock_enqueue(ap_ioqueue_t *vec, ap_ioblock_t *toadd)
> > {
> >     vec->tail->next = toadd;
> >     toadd->prev = vec->tail;
> >     vec->tail = toadd;
> >     return vec;
> > }
> >
> > ap_ioqueue_t *ap_ioqueue_merge(ap_ioqueue_t *vec, ap_ioqueue_t *toadd)
> > {
> >     vec->tail->next = toadd->head;
> >     toadd->head->prev = vec->tail;
> >     vec->tail = toadd->tail;
> >     return vec;
> > }
> >
> >
> > ap_ioblock.h:
> > -------------
> >
> > /* ====================================================================
> >  * The Apache Software License, Version 1.1
> >  *
> >  * Copyright (c) 2000 The Apache Software Foundation.  All rights
> >  * reserved.
> >  *
> >  * Redistribution and use in source and binary forms, with or without
> >  * modification, are permitted provided that the following conditions
> >  * are met:
> >  *
> >  * 1. Redistributions of source code must retain the above copyright
> >  *    notice, this list of conditions and the following disclaimer.
> >  *
> >  * 2. Redistributions in binary form must reproduce the above copyright
> >  *    notice, this list of conditions and the following disclaimer in
> >  *    the documentation and/or other materials provided with the
> >  *    distribution.
> >  *
> >  * 3. The end-user documentation included with the redistribution,
> >  *    if any, must include the following acknowledgment:
> >  *       "This product includes software developed by the
> >  *        Apache Software Foundation (http://www.apache.org/)."
> >  *    Alternately, this acknowledgment may appear in the software itself,
> >  *    if and wherever such third-party acknowledgments normally appear.
> >  *
> >  * 4. The names "Apache" and "Apache Software Foundation" must
> >  *    not be used to endorse or promote products derived from this
> >  *    software without prior written permission. For written
> >  *    permission, please contact apache@apache.org.
> >  *
> >  * 5. Products derived from this software may not be called "Apache",
> >  *    nor may "Apache" appear in their name, without prior written
> >  *    permission of the Apache Software Foundation.
> >  *
> >  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> >  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> >  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> >  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> >  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> >  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> >  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> >  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> >  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> >  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> >  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >  * SUCH DAMAGE.
> >  * ====================================================================
> >  *
> >  * This software consists of voluntary contributions made by many
> >  * individuals on behalf of the Apache Software Foundation.  For more
> >  * information on the Apache Software Foundation, please see
> >  * <http://www.apache.org/>.
> >  *
> >  * This file was originally written by Ryan Bloom for Covalent Technologies
> >  * and gifted exclusively to the The Apache Software Foundation in June 2000.
> >  */
> >
> > #ifndef AP_IOBLOCK_H
> > #define AP_IOBLOCK_H
> >
> > #include "apr_pools.h"
> > #include "apr_file_io.h"
> > #include "ap_config.h"
> >
> > #define AP_WRITABLE            1
> > #define AP_NOT_WRITABLE        2
> > #define AP_FILE_DESC           4
> >
> > struct ap_ioblock_t {
> >     ap_pool_t *p;
> >     void *vec;
> >     int len;
> >     ap_file_t *fd;
> >     int bitmask;
> >     struct ap_ioblock_t *next;
> >     struct ap_ioblock_t *prev;
> > };
> >
> > struct ap_ioqueue_t {
> >     ap_pool_t *p;
> >     struct ap_ioblock_t *head;
> >     struct ap_ioblock_t *tail;
> > };
> >
> > typedef struct ap_ioblock_t ap_ioblock_t;
> > typedef struct ap_ioqueue_t ap_ioqueue_t;
> >
> > API_EXPORT(ap_ioblock_t *) ap_create_ioblock(ap_pool_t *p, const void *v,
> >                                            int length);
> > API_EXPORT(ap_status_t) ap_split_ioblock(ap_ioblock_t *vec, int offset);
> > API_EXPORT(ap_ioblock_t *) ap_add_ioblock(ap_ioblock_t *vec, const void *v,
> >                                         int length, int front);
> > API_EXPORT(ap_status_t) ap_set_ioblock_writable(ap_ioblock_t *vec);
> >
> > API_EXPORT(ap_ioqueue_t *) ap_start_ioqueue(ap_ioblock_t *b);
> > API_EXPORT(ap_ioqueue_t *) ap_create_ioqueue(ap_pool_t *p, const void *v,
> >                                            int length);
> > API_EXPORT(ap_ioqueue_t *) ap_ioblock_enqueue(ap_ioqueue_t *vec, ap_ioblock_t *toadd);
> > API_EXPORT(ap_ioqueue_t *) ap_ioqueue_merge(ap_ioqueue_t *vec, ap_ioqueue_t *toadd);
> >
> > #endif
> >
> >
> > mod_gargle.c:
> > -------------
> >
> > /* ====================================================================
> >  * The Apache Software License, Version 1.1
> >  *
> >  * Copyright (c) 2000 The Apache Software Foundation.  All rights
> >  * reserved.
> >  *
> >  * Redistribution and use in source and binary forms, with or without
> >  * modification, are permitted provided that the following conditions
> >  * are met:
> >  *
> >  * 1. Redistributions of source code must retain the above copyright
> >  *    notice, this list of conditions and the following disclaimer.
> >  *
> >  * 2. Redistributions in binary form must reproduce the above copyright
> >  *    notice, this list of conditions and the following disclaimer in
> >  *    the documentation and/or other materials provided with the
> >  *    distribution.
> >  *
> >  * 3. The end-user documentation included with the redistribution,
> >  *    if any, must include the following acknowledgment:
> >  *       "This product includes software developed by the
> >  *        Apache Software Foundation (http://www.apache.org/)."
> >  *    Alternately, this acknowledgment may appear in the software itself,
> >  *    if and wherever such third-party acknowledgments normally appear.
> >  *
> >  * 4. The names "Apache" and "Apache Software Foundation" must
> >  *    not be used to endorse or promote products derived from this
> >  *    software without prior written permission. For written
> >  *    permission, please contact apache@apache.org.
> >  *
> >  * 5. Products derived from this software may not be called "Apache",
> >  *    nor may "Apache" appear in their name, without prior written
> >  *    permission of the Apache Software Foundation.
> >  *
> >  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> >  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> >  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> >  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> >  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> >  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> >  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> >  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> >  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> >  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> >  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >  * SUCH DAMAGE.
> >  * ====================================================================
> >  *
> >  * This software consists of voluntary contributions made by many
> >  * individuals on behalf of the Apache Software Foundation.  For more
> >  * information on the Apache Software Foundation, please see
> >  * <http://www.apache.org/>.
> >  *
> >  * Portions of this software are based upon public domain software
> >  * originally written at the National Center for Supercomputing Applications,
> >  * University of Illinois, Urbana-Champaign.
> >  */
> >
> > #include "httpd.h"
> > #include "ap_hooks.h"
> > #include "ap_ioblock.h"
> > #include "http_config.h"
> > #include "http_request.h"
> > #include "http_protocol.h"
> >
> > module MODULE_VAR_EXPORT gargle_module;
> >
> > typedef struct gargle_rec {
> >     int on;
> > } gargle_rec;
> >
> >
> > ap_ioqueue_t *gargle_filter(request_rec *r, ap_ioqueue_t *strs);
> >
> > static void *create_gargle_config(ap_pool_t *p, char *dummy)
> > {
> >     gargle_rec *new = (gargle_rec *) ap_pcalloc(p, sizeof(gargle_rec));
> >
> >     new->on = 0;
> >     return (void *)new;
> > }
> >
> > ap_ioqueue_t *gargle_filter(request_rec *r, ap_ioqueue_t *strs)
> > {
> >     static int dummy = 0;
> >     ap_ioblock_t *dptr = strs->head;
> >
> >     while (dptr != NULL) {
> >         if (dptr->len > 10) {
> >             ap_ioblock_t *temp;
> >
> >             ap_split_ioblock(dptr, 9);
> >             dptr = dptr->next;
> >             ap_split_ioblock(dptr, 1);
> >             ap_split_ioblock(dptr->next, 1);
> >
> >             temp = dptr->next;
> >             temp->prev = dptr->prev;
> >             dptr->next = temp->next;
> >             temp->next = dptr;
> >             dptr->prev->next = temp;
> >             dptr->prev = temp;
> >         }
> > #if 0
> >         if (dummy == 0) {
> >             ap_ioqueue_t *d2 = ap_start_ioqueue(dptr->next);
> >             dummy = 1;
> >             dptr->next = NULL;
> >             return d2;
> >         }
> > #endif
> >         dptr = dptr->next;
> >     }
> >     return NULL;
> > }
> >
> > static const char *gargle_on(cmd_parms *cmd, void *dummy, char *arg)
> > {
> >     gargle_rec *cfg = (gargle_rec *)dummy;
> >
> >     cfg->on = atoi(arg);
> >
> >     return NULL;
> > }
> >
> > static const command_rec gargle_cmds[] = {
> >     {"GargleIt", gargle_on, NULL, ACCESS_CONF, TAKE1,
> >      "should this request be gargled"},
> >     {NULL}
> > };
> >
> > static int gargle_insert_filter(request_rec *r)
> > {
> >     gargle_rec *cfg = (gargle_rec *)ap_get_module_config(r->per_dir_config,
> >                                                          &gargle_module);
> >
> >     if (cfg->on) {
> >         ap_rhook_filter(gargle_filter, r, NULL, NULL, AP_HOOK_FILTER);
> >     }
> >     return DECLINED;
> > }
> >
> > static void register_hooks(void)
> > {
> >     ap_hook_insert_filter(gargle_insert_filter, NULL, NULL, AP_HOOK_FILTER);
> > }
> >
> > module MODULE_VAR_EXPORT gargle_module =
> > {
> >     STANDARD20_MODULE_STUFF,
> >     create_gargle_config,     /* dir config creater */
> >     NULL,                     /* dir merger --- default is to override */
> >     NULL,                     /* server config */
> >     NULL,                     /* merge server config */
> >     gargle_cmds,              /* command ap_table_t */
> >     NULL,                     /* handlers */
> >     register_hooks            /* register hooks */
> > };
> >
> > _______________________________________________________________________________
> > Ryan Bloom                        rbb@apache.org
> > 406 29th St.
> > San Francisco, CA 94131
> > -------------------------------------------------------------------------------
> >
> >

-- 
Greg Stein, http://www.lyra.org/

Mime
View raw message