httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@covalent.net
Subject [PATCH] hook based filters take 4
Date Tue, 27 Jun 2000 00:14:05 GMT

This is the next step in the hook based filters.  I said earlier today
that it was recursive.  That was a lie.  Sorry.  :-)  In reality, it is
just a bunch of calls down the stack.  Filters move onto the next call by
just using the macro NEXT_FILTER().  This can be seen in mod_gargle.c.

This makes the output to the network a filter itself, which can be seen in
core_write, which is what actually writes out to the network.  I believe
that with this, a lot of what is in buff.c can be removed, and the buffers
can become smaller and a bit cleaner.

One of the things we will obviously need to do, is take all of the
ap_b(puts|printf|...) calls and make them work with the ioblocks, but that
is absolutely trivial.  I haven't done it, because I wanted to post this
patch.

This patch has some issues, because it is trying to work around some
hokiness in the current code, but if accepted, it will be cleaned up
either just before or just after it is committed.

Ryan

? include/ap_ioblock.h
? main/ap_ioblock.c
? modules/extra/mod_gargle.c
Index: 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
--- include/ap_hooks.h	2000/05/27 22:53:46	1.20
+++ include/ap_hooks.h	2000/06/27 00:05:34
@@ -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: include/httpd.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
retrieving revision 1.63
diff -u -d -b -w -u -r1.63 httpd.h
--- include/httpd.h	2000/06/24 19:31:41	1.63
+++ include/httpd.h	2000/06/27 00:05:34
@@ -81,6 +81,7 @@
 #include "apr_network_io.h"
 #include "buff.h"
 #include "ap_mmn.h"
+#include "ap_hooks.h"
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -596,6 +597,11 @@
 				 * pointer back to the main request.
 				 */
 
+    AP_RHOOK_STRUCT (
+        AP_RHOOK_LINK(filter)   /* per-request filter I/O hook. */
+    );
+    struct ap_ioqueue_t *keep_around; 
+
     /* Info about the request itself... we begin with stuff that only
      * protocol.c should ever touch...
      */
@@ -643,6 +649,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 */
@@ -1055,6 +1062,14 @@
 # define ap_strstr_c(s, c)	strstr(s, c)
 
 #endif
+
+/* This definately doesn't belong here, but the include headers are all screwed
+ * up when I put it in buff.h.  What I really want to do is to clean out
+ * buff.[ch] and put it there, but that will have to wait, because it is a
+ * big chunk of work.
+ */
+API_EXPORT(int) ap_bwrite_block(request_rec *r, BUFF *fb, struct ap_ioqueue_t *strs);
+
 
 #ifdef __cplusplus
 }
Index: main/Makefile.in
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/Makefile.in,v
retrieving revision 1.14
diff -u -d -b -w -u -r1.14 Makefile.in
--- main/Makefile.in	2000/06/22 18:28:06	1.14
+++ main/Makefile.in	2000/06/27 00:05:47
@@ -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_debug.c
+	util_charset.c util_debug.c ap_ioblock.c
 
 include $(top_srcdir)/build/ltlib.mk
 
Index: main/buff.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/buff.c,v
retrieving revision 1.54
diff -u -d -b -w -u -r1.54 buff.c
--- main/buff.c	2000/06/17 01:29:29	1.54
+++ main/buff.c	2000/06/27 00:05:47
@@ -57,6 +57,7 @@
  */
 
 #include "ap_config.h"
+#include "ap_ioblock.h"
 #include "httpd.h"
 #include "http_main.h"
 #include "http_log.h"
@@ -1391,3 +1392,64 @@
     ap_bpush_iol(fb, iol);
     return fb;
 }
+
+API_EXPORT(int) ap_bwrite_block(request_rec *r, BUFF *fb, ap_ioqueue_t *strs)
+{ 
+    ap_ioblock_t *dptr;
+    ap_ssize_t bytes_written = 0;
+    ap_ssize_t bytes;
+    int len = 0;
+    int rv = APR_EINIT;
+
+/* When we save unwritten things into the BUFF, we also have to take them
+ * back out when we are called here again.
+ 
+    if (fb->unwritten) {
+        strs = ap_ioqueue_merge(r->unwritten, strs);
+    }
+ */
+
+    for (dptr=strs->head; dptr != strs->tail; dptr = dptr->next) {
+        len += dptr->len;
+    }
+
+    if (len > LARGE_WRITE_THRESHOLD) {
+        for (dptr=strs->head; dptr != NULL; dptr = dptr->next) {
+
+            /* This can be made MUCH cleaner, but first we have to clean
+             * out buff.c.
+             */
+            rv = iol_write(fb->iol, dptr->vec, dptr->len, &bytes);
+            if (rv == APR_SUCCESS) {
+                bytes_written += bytes;
+                continue;
+            }
+            else {
+                fb->saved_errno = rv;
+                if (ap_canonical_error(rv) != APR_EAGAIN) {
+                    doerror(fb, B_WR);
+                }
+            }
+        }
+    }
+    else {
+        /* obvious optimization, remove the memcpy by just saving aside the
+         * ioqueue that must be written.  For right now, use the current
+         * BUFF code.  This could probably be gotten rid of very quickly,
+         * but I want to post the patch.  I'll remove all of this immediately
+         * after posting.
+        r->unwritten = ap_ioqueue_merge(r->unwritten, strs); 
+         */
+        for (dptr=strs->head; dptr != NULL; dptr = dptr->next) {
+            rv = ap_bwrite(fb, dptr->vec, dptr->len, &bytes);
+            bytes_written += bytes;
+        }
+        return bytes_written;
+    }
+    if (rv == APR_SUCCESS) {
+        return bytes_written;
+    }
+    else return rv;
+}
+
+
Index: main/http_core.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
retrieving revision 1.81
diff -u -d -b -w -u -r1.81 http_core.c
--- main/http_core.c	2000/06/24 17:33:55	1.81
+++ main/http_core.c	2000/06/27 00:05:47
@@ -58,6 +58,7 @@
 
 #define CORE_PRIVATE
 #include "ap_config.h"
+#include "ap_ioblock.h"
 #include "apr_lib.h"
 #include "httpd.h"
 #include "http_config.h"
@@ -108,6 +109,11 @@
 #endif
 #endif /* USE_MMAP_FILES */
 
+#define SET_BYTES_SENT(r) \
+  do { if (r->sent_bodyct) \
+          ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
+  } while (0)
+
 /* Server core module... This module provides support for really basic
  * server operations, including options and commands which control the
  * operation of other modules.  Consider this the bureaucracy module.
@@ -2765,8 +2771,6 @@
 
 	rangestatus = ap_set_byterange(r);
 
-	ap_send_http_header(r);
-	
 	if (!r->header_only) {
 	    if (!rangestatus) {
 		ap_send_fd(fd, r);
@@ -2808,8 +2812,6 @@
 	}
 
 	rangestatus = ap_set_byterange(r);
-	ap_send_http_header(r);
-	
 	if (!r->header_only) {
 	    if (!rangestatus) {
 		ap_send_mmap(mm, r, 0, r->finfo.size);
@@ -2851,6 +2853,29 @@
 static unsigned short core_port(const request_rec *r)
     { return DEFAULT_HTTP_PORT; }
 
+static int core_write(ap_filter_t filter, request_rec *r, ap_ioqueue_t *strs)
+{
+    int n;
+
+    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);
+        ap_bflush(r->connection->client);
+    }
+
+
+    n = ap_bwrite_block(r, r->connection->client, strs);
+    SET_BYTES_SENT(r);
+    return n;
+}
+
+static void insert_filter(request_rec *r)
+{
+    ap_rhook_filter(core_write, r, NULL, NULL, AP_HOOK_REALLY_LAST);
+}
+
 static void register_hooks(void)
 {
     ap_hook_post_config(core_post_config,NULL,NULL,AP_HOOK_REALLY_FIRST);
@@ -2863,6 +2888,10 @@
     /* FIXME: I suspect we can eliminate the need for these - Ben */
     ap_hook_type_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
     ap_hook_access_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
+      
+    /* FIXME::::  I think this allows us to remove most of the code from buff. 
+       :-) */
+    ap_hook_insert_filter(insert_filter, NULL, NULL, AP_HOOK_MIDDLE);
 }
 
 API_VAR_EXPORT module core_module = {
Index: main/http_protocol.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
retrieving revision 1.87
diff -u -d -b -w -u -r1.87 http_protocol.c
--- main/http_protocol.c	2000/06/24 19:31:41	1.87
+++ main/http_protocol.c	2000/06/27 00:05:47
@@ -65,6 +65,7 @@
 
 #define CORE_PRIVATE
 #include "ap_config.h"
+#include "ap_ioblock.h"
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
@@ -96,7 +97,6 @@
           ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
   } while (0)
 
-
 /* if this is the first error, then log an INFO message and shut down the
  * connection.
  */
@@ -1811,6 +1811,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);
@@ -2406,7 +2410,6 @@
     if (length == 0)
         return 0;
 
-
     length += offset;
     while (!r->connection->aborted && offset < length) {
         if (length - offset > MMAP_SEGMENT_SIZE) {
@@ -2431,107 +2434,72 @@
 
 API_EXPORT(int) ap_rputc(int c, request_rec *r)
 {
-    if (r->connection->aborted)
-        return EOF;
-
-    if (ap_bputc(c, r->connection->client) < 0) {
-        check_first_conn_error(r, "rputc", 0);
-        return EOF;
-    }
-    SET_BYTES_SENT(r);
-    return c;
+    SETUP_FILTERS
+    NEXT_FILTER(filters, r, ap_create_ioqueue(r->pool, (const char *)&c, 1)); 
 }
 
 API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
 {
-    int rcode;
-
-    if (r->connection->aborted)
-        return EOF;
-    
-    rcode = ap_bputs(str, r->connection->client);
-    if (rcode < 0) {
-        check_first_conn_error(r, "rputs", 0);
-        return EOF;
-    }
-    SET_BYTES_SENT(r);
-    return rcode;
+    SETUP_FILTERS
+    NEXT_FILTER(filters, r, ap_create_ioqueue(r->pool, str, strlen(str))); 
 }
 
 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;
-
-    /* ### should loop to avoid partial writes */
-    rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
-    if (n < 0) {
-        check_first_conn_error(r, "rwrite", rv);
-        return EOF;
-    }
-    SET_BYTES_SENT(r);
-    return n;
+    SETUP_FILTERS
+    NEXT_FILTER(filters, r, ap_create_ioqueue(r->pool, buf, nbyte)); 
 }
 
 API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
 {
-    int n;
-
-    if (r->connection->aborted)
-        return EOF;
+    char *str;
 
-    n = ap_vbprintf(r->connection->client, fmt, va);
+    SETUP_FILTERS
+    str = ap_pvsprintf(r->pool, fmt, va);
 
-    if (n < 0) {
-        check_first_conn_error(r, "vrprintf", 0);
-        return EOF;
-    }
-    SET_BYTES_SENT(r);
-    return n;
+    NEXT_FILTER(filters, r, ap_create_ioqueue(r->pool, str, strlen(str))); 
 }
 
 API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
 {
     va_list va;
     int n;
+    char *str;
 
-    if (r->connection->aborted)
-        return EOF;
+    SETUP_FILTERS
 
     va_start(va, fmt);
-    n = ap_vbprintf(r->connection->client, fmt, va);
-    va_end(va);
+    str = ap_pvsprintf(r->pool, fmt, va);
+    va_end(vlist);
 
-    if (n < 0) {
-        check_first_conn_error(r, "rprintf", 0);
-        return EOF;
-    }
-    SET_BYTES_SENT(r);
-    return n;
+    n = strlen(str);
+
+    NEXT_FILTER(filters, r, ap_create_ioqueue(r->pool, str, n)); 
 }
 
 API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r, ...)
 {
-    va_list va;
-    int n;
-
-    if (r->connection->aborted)
-        return EOF;
+    va_list args;
+    int j, k;
+    const char *x;
+    ap_ioqueue_t *strs = NULL;
 
-    va_start(va, r);
-    n = ap_vbputstrs(r->connection->client, va);
-    va_end(va);
+    SETUP_FILTERS
 
-    if (n < 0) {
-        check_first_conn_error(r, "rvputs", 0);
-        return EOF;
+    va_start(args, r);
+    for (k = 0;;) {
+        x = va_arg(args, const char *);
+        if (x == NULL)
+            break;
+        j = strlen(x);
+        if (k == 0) {
+            strs = ap_create_ioqueue(r->pool, x, j);
     }
-
-    SET_BYTES_SENT(r);
-    return n;
+        else {
+            strs = ap_ioblock_enqueue(strs, ap_create_ioblock(r->pool, x, j));
+        }
+    }
+    NEXT_FILTER(filters, r, strs); 
 }
 
 API_EXPORT(int) ap_rflush(request_rec *r)
@@ -2597,7 +2565,6 @@
     }
 
     if (status == HTTP_NO_CONTENT) {
-        ap_send_http_header(r);
         ap_finalize_request_protocol(r);
         return;
     }
@@ -2634,7 +2601,6 @@
             ap_table_setn(r->headers_out, "Allow", make_allow(r));
         }
 
-        ap_send_http_header(r);
 
         if (r->header_only) {
             ap_finalize_request_protocol(r);
@@ -2942,3 +2908,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: main/http_request.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
retrieving revision 1.35
diff -u -d -b -w -u -r1.35 http_request.c
--- main/http_request.c	2000/06/24 17:33:57	1.35
+++ main/http_request.c	2000/06/27 00:05:48
@@ -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"

___________________________
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;
    b->queue = q; 
    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);
    q->head->queue = q;

    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->queue = vec->queue;
    vector->queue->tail = vector;
    
    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;

    vector->queue = vec->queue;

    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) 
{
    if (!vec) {
        return 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 "httpd.h"
#include "ap_hooks.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 *queue;
};

struct ap_ioqueue_t {
    ap_pool_t *p;
    void *ctx;
    struct ap_ioblock_t *head;
    struct ap_ioblock_t *tail;
};

struct ap_filter_t {
    ap_array_header_t *filter_list;
    int current_filter;
};

typedef struct ap_ioblock_t ap_ioblock_t;
typedef struct ap_ioqueue_t ap_ioqueue_t;
typedef struct ap_filter_t  ap_filter_t;

AP_DECLARE_RHOOK(int, filter, \
                (ap_filter_t filter, request_rec *r, ap_ioqueue_t *strs))

#define SETUP_FILTERS \
    ap_filter_t filters; \
    int num_filters = r->_hooks.link_filter->nelts; \
    \
    if (r->connection->aborted) \
        return EOF; \
    \
    if (r->keep_around == NULL) { \
        r->keep_around = ap_pcalloc(r->pool, num_filters * \
                                    sizeof(ap_ioqueue_t *)); \
    } \
    \
    filters.filter_list = r->_hooks.link_filter; \
    filters.current_filter = 0;

#define NEXT_FILTER(filter, r, iob) \
    { \
        LINK_filter *hook; \
        hook = (LINK_filter *)r->_hooks.link_filter->elts; \
        return hook[filter.current_filter++].pFunc(filter, r, iob); \
    }

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;


int gargle_filter(ap_filter_t 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;
}

int gargle_filter(ap_filter_t filter, request_rec *r, ap_ioqueue_t *strs)
{
    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;
        }
        dptr = dptr->next;
    }
    NEXT_FILTER(filter, r, strs);
}

static const char *gargle_on(cmd_parms *cmd, void *dummy, const char *arg)
{
    gargle_rec *cfg = (gargle_rec *)dummy;

    cfg->on = atoi(arg);

    return NULL;
}

static const command_rec gargle_cmds[] = {
    AP_INIT_TAKE1("GargleIt", gargle_on, NULL, ACCESS_CONF, 
     "should this request be gargled"),
    {NULL}
}; 

static void 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);
    }
}

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
-------------------------------------------------------------------------------


Mime
View raw message