]> granicus.if.org Git - apache/commitdiff
Add the ability to register filters. This commit introduces a warning
authorRyan Bloom <rbb@apache.org>
Fri, 28 Jul 2000 20:31:02 +0000 (20:31 +0000)
committerRyan Bloom <rbb@apache.org>
Fri, 28 Jul 2000 20:31:02 +0000 (20:31 +0000)
into the build.  This warning will be removed automatically, as soon as
we decide on a prototype for the function causing the warning.  That
decision is tied to which filtering mechanism we decide on.
Submitted by: Ryan Bloom and Greg Stein

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85926 13f79535-47bb-0310-9956-ffa450edef68

include/httpd.h
include/util_filter.h [new file with mode: 0644]
modules/http/http_protocol.c
modules/http/http_request.c
server/Makefile.in
server/util_filter.c [new file with mode: 0644]

index ae7843a0353ac81e5e6238c005cf6838a325b584..2c2f5ed20be73001fe73957ca9e77f289378054d 100644 (file)
@@ -731,7 +731,9 @@ struct request_rec {
 #ifdef APACHE_XLATE
     struct ap_rr_xlate *rrx;
 #endif /*APACHE_XLATE*/
-    
+
+    struct ap_filter_t *filters;
+
 /* Things placed at the end of the record to avoid breaking binary
  * compatibility.  It would be nice to remember to reorder the entire
  * record to improve 64bit alignment the next time we need to break
diff --git a/include/util_filter.h b/include/util_filter.h
new file mode 100644 (file)
index 0000000..f2f564a
--- /dev/null
@@ -0,0 +1,220 @@
+/* ====================================================================
+ * 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/>.
+ */
+
+#ifndef AP_FILTER_H
+#define AP_FILTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef APR_HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#include "httpd.h"
+#include "apr.h"
+
+/*
+ * FILTER CHAIN
+ *
+ * Filters operate using a "chaining" mechanism. The filters are chained
+ * together into a sequence. When output is generated, it is passed through
+ * each of the filters on this chain, until it reaches the end (or "bottom")
+ * and is placed onto the network.
+ *
+ * The top of the chain, the code generating the output, is typically called
+ * a "content generator." The content generator's output is fed into the
+ * filter chain using the standard Apache output mechanisms: ap_rputs(),
+ * ap_rprintf(), ap_rwrite(), etc.
+ *
+ * Each filter is defined by a callback. This callback takes the output from
+ * the previous filter (or the content generator if there is no previous
+ * filter), operates on it, and passes the result to the next filter in the
+ * chain. This pass-off is performed using the ap_fc_* functions, such as
+ * ap_fc_puts(), ap_fc_printf(), ap_fc_write(), etc.
+ *
+ * When content generation is complete, the system will pass an "end of
+ * stream" marker into the filter chain. The filters will use this to flush
+ * out any internal state and to detect incomplete syntax (for example, an
+ * unterminated SSI directive).
+ */
+
+/* forward declare the filter type */
+typedef struct ap_filter_t ap_filter_t;
+
+/*
+ * ap_filter_func:
+ *
+ * This function type is used for filter callbacks. It will be passed a
+ * pointer to "this" filter, and a "bucket" containing the content to be
+ * filtered.
+ *
+ * In filter->ctx, the callback will find its context. This context is
+ * provided here, so that a filter may be installed multiple times, each
+ * receiving its own per-install context pointer.
+ *
+ * Callbacks are associated with a filter definition, which is specified
+ * by name. See ap_register_filter() for setting the association between
+ * a name for a filter and its associated callback (and other information).
+ *
+ * The *bucket structure (and all those referenced by ->next and ->prev)
+ * should be considered "const". The filter is allowed to modify the
+ * next/prev to insert/remove/replace elements in the bucket list, but
+ * the types and values of the individual buckets should not be altered.
+ */
+typedef ap_status_t (*ap_filter_func)();
+
+/*
+ * ap_filter_type:
+ *
+ * Filters have different types/classifications. These are used to group
+ * and sort the filters to properly sequence their operation.
+ *
+ * AP_FTYPE_CONTENT:
+ *     These filters are used to alter the content that is passed through
+ *     them. Examples are SSI or PHP.
+ *
+ * AP_FTYPE_CONNECTION:
+ *     These filters will alter the content, but in ways that are more
+ *     strongly associated with the output connection. Examples are
+ *     compression, character recoding, or chunked transfer coding.
+ *
+ *     It is important to note that these types of filters are not allowed
+ *     in a sub-request. A sub-requests output can certainly be filtered
+ *     by AP_FTYPE_CONTENT filters, but all of the "final processing" is
+ *     determined by the main request.
+ *
+ * The types have a particular sort order, which allows us to insert them
+ * into the filter chain in a determistic order. Within a particular grouping,
+ * the ordering is equivalent to the order of calls to ap_add_filter().
+ */
+typedef enum {
+    AP_FTYPE_CONTENT,
+    AP_FTYPE_CONNECTION
+} ap_filter_type;
+
+/*
+ * ap_filter_t:
+ *
+ * This is the request-time context structure for an installed filter (in
+ * the output filter chain). It provides the callback to use for filtering,
+ * the request this filter is associated with (which is important when
+ * an output chain also includes sub-request filters), the context for this
+ * installed filter, and the filter ordering/chaining fields.
+ *
+ * Filter callbacks are free to use ->ctx as they please, to store context
+ * during the filter process. Generally, this is superior over associating
+ * the state directly with the request. A callback should not change any of
+ * the other fields.
+ */
+struct ap_filter_t {
+    ap_filter_func filter_func;
+
+    void *ctx;
+
+    ap_filter_type ftype;
+    ap_filter_t *next;
+};
+
+/*
+ * ap_register_filter():
+ *
+ * This function is used to register a filter with the system. After this
+ * registration is performed, then a filter may be added into the filter
+ * chain by using ap_add_filter() and simply specifying the name.
+ *
+ * The filter's callback and type should be passed.
+ */
+API_EXPORT(void) ap_register_filter(const char *name,
+                                    ap_filter_func filter_func,
+                                    ap_filter_type ftype);
+
+/*
+ * ap_add_filter():
+ *
+ * Adds a named filter into the filter chain on the specified request record.
+ * The filter will be installed with the specified context pointer.
+ *
+ * Filters added in this way will always be placed at the end of the filters
+ * that have the same type (thus, the filters have the same order as the
+ * calls to ap_add_filter). If the current filter chain contains filters
+ * from another request, then this filter will be added before those other
+ * filters.
+ */
+API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r);
+
+
+/*
+ * Things to do later:
+ * Add parameters to ap_filter_func type.  Those parameters will be something
+ *     like:
+ *         (request_rec *r, ap_filter_t *filter, ap_data_list *the_data)
+ *      obviously, the request_rec is the current request, and the filter
+ *      is the current filter stack.  The data_list is a bucket list or
+ *      bucket_brigade, but I am trying to keep this patch neutral.  (If this
+ *      comment breaks that, well sorry, but the information must be there
+ *      somewhere.  :-)
+ *
+ * Add a function like ap_pass_data.  This function will basically just
+ * call the next filter in the chain, until the current filter is NULL.  If the
+ * current filter is NULL, that means that nobody wrote to the network, and
+ * we have a HUGE bug, so we need to return an error and log it to the 
+ * log file.
+ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !AP_FILTER_H */
index 87ae898513958b38bb31234d218f8fcbd411c88b..5b8c3c22b7a82bc251b68ccaa81ba2e19bd6924b 100644 (file)
@@ -1278,8 +1278,19 @@ void ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r)
     rnew->main = (request_rec *) r;
 }
 
+static void end_output_stream(request_rec *r)
+{
+    /*
+    ** ### place holder to tell filters that no more content will be
+    ** ### arriving. typically, they will flush any pending content
+    */
+}
+
 void ap_finalize_sub_req_protocol(request_rec *sub)
 {
+    /* tell the filter chain there is no more content coming */
+    end_output_stream(sub);
+
     SET_BYTES_SENT(sub->main);
 }
 
@@ -1833,11 +1844,6 @@ API_EXPORT(void) ap_send_http_header(request_rec *r)
 #endif /*APACHE_XLATE*/
 }
 
-static void flush_filters(request_rec *r)
-{
-    /* ### place holder to flush pending content through the filters */
-}
-
 /* finalize_request_protocol is called at completion of sending the
  * response.  It's sole purpose is to send the terminating protocol
  * information for any wrappers around the response message body
@@ -1845,7 +1851,8 @@ static void flush_filters(request_rec *r)
  */
 API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
 {
-    flush_filters(r);
+    /* tell the filter chain there is no more content coming */
+    end_output_stream(r);
 
     if (r->chunked && !r->connection->aborted) {
 #ifdef APACHE_XLATE
index 4c3e9730a3f57cdb394401324472e9cef3ccae1a..9bde8654f124a66d1b1610fa1ee3ea7b6a30c70d 100644 (file)
@@ -770,6 +770,9 @@ API_EXPORT(request_rec *) ap_sub_req_method_uri(const char *method,
     rnew->htaccess       = r->htaccess;
     rnew->per_dir_config = r->server->lookup_defaults;
 
+    /* start with the same set of output filters */
+    rnew->filters = r->filters;
+
     ap_set_sub_req_protocol(rnew, r);
 
     /* would be nicer to pass "method" to ap_set_sub_req_protocol */
@@ -858,6 +861,9 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file,
     rnew->htaccess       = r->htaccess;
     rnew->chunked        = r->chunked;
 
+    /* start with the same set of output filters */
+    rnew->filters = r->filters;
+
     ap_set_sub_req_protocol(rnew, r);
     fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
 
@@ -961,16 +967,22 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file,
 
 API_EXPORT(int) ap_run_sub_req(request_rec *r)
 {
+    int retval;
+
+    /* see comments in process_request_internal() */
+    ap_run_insert_filter(r);
+
 #ifndef APACHE_XLATE
-    int retval = ap_invoke_handler(r);
+    retval = ap_invoke_handler(r);
 #else /*APACHE_XLATE*/
-    /* Save the output conversion setting of the caller across subrequests */
-    int retval;
-    ap_xlate_t *saved_xlate;
+    {
+        /* Save the output conversion setting across subrequests */
+        ap_xlate_t *saved_xlate;
 
-    ap_bgetopt(r->connection->client, BO_WXLATE, &saved_xlate);
-    retval  = ap_invoke_handler(r);
-    ap_bsetopt(r->connection->client, BO_WXLATE, &saved_xlate);
+        ap_bgetopt(r->connection->client, BO_WXLATE, &saved_xlate);
+        retval  = ap_invoke_handler(r);
+        ap_bsetopt(r->connection->client, BO_WXLATE, &saved_xlate);
+    }
 #endif /*APACHE_XLATE*/
     ap_finalize_sub_req_protocol(r);
     return retval;
index 497079cf13addd0f4143763ef0a3c577c887bbcc..a5e5432ee768c05e5f6a272b371e87ef97b5bea7 100644 (file)
@@ -8,7 +8,8 @@ LTLIBRARY_SOURCES = \
        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 iol_socket.c listen.c \
-        mpm_common.c util_charset.c util_debug.c util_xml.c
+        mpm_common.c util_charset.c util_debug.c util_xml.c \
+       util_filter.c
 
 include $(top_srcdir)/build/ltlib.mk
 
diff --git a/server/util_filter.c b/server/util_filter.c
new file mode 100644 (file)
index 0000000..77bdc98
--- /dev/null
@@ -0,0 +1,146 @@
+/* ====================================================================
+ * 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/>.
+ */
+
+#include "util_filter.h"
+
+/*
+ * ap_filter_rec_t:
+ *
+ * This (internal) structure is used for recording information about the
+ * registered filters. It associates a name with the filter's callback
+ * and filter type.
+ *
+ * At the moment, these are simply linked in a chain, so a ->next pointer
+ * is available.
+ */
+typedef struct ap_filter_rec_t {
+    const char *name;
+    ap_filter_func filter_func;
+    ap_filter_type ftype;
+
+    struct ap_filter_rec_t *next;
+} ap_filter_rec_t;
+
+/* ### make this visible for direct manipulation?
+   ### use a hash table
+*/
+static ap_filter_rec_t *registered_filters = NULL;
+
+/* NOTE: Apache's current design doesn't allow a pool to be passed thu,
+   so we depend on a global to hold the correct pool
+*/
+#define FILTER_POOL     ap_global_hook_pool
+#include "ap_hooks.h"   /* for ap_global_hook_pool */
+
+/*
+** This macro returns true/false if a given filter should be inserted BEFORE
+** another filter. This will happen when one of: 1) there isn't another
+** filter; 2) that filter has a higher filter type (class); 3) that filter
+** corresponds to a different request.
+*/
+#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
+                                       || (before_this)->ftype > (f)->ftype)
+
+
+static ap_status_t filter_cleanup(void *ctx)
+{
+    registered_filters = NULL;
+    return APR_SUCCESS;
+}
+
+API_EXPORT(void) ap_register_filter(const char *name,
+                                    ap_filter_func filter_func,
+                                    ap_filter_type ftype)
+{
+    ap_filter_rec_t *frec = ap_palloc(FILTER_POOL, sizeof(*frec));
+
+    frec->name = name;
+    frec->filter_func = filter_func;
+    frec->ftype = ftype;
+
+    frec->next = registered_filters;
+    registered_filters = frec;
+
+    ap_register_cleanup(FILTER_POOL, NULL, filter_cleanup, NULL);
+}
+
+API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
+{
+    ap_filter_rec_t *frec = registered_filters;
+
+    for (; frec != NULL; frec = frec->next) {
+        if (!strcasecmp(name, frec->name)) {
+            ap_filter_t *f = ap_pcalloc(r->pool, sizeof(*f));
+
+            f->filter_func = frec->filter_func;
+            f->ctx = ctx;
+            f->ftype = frec->ftype;
+
+            if (INSERT_BEFORE(f, r->filters)) {
+                f->next = r->filters;
+                r->filters = f;
+            }
+            else {
+                ap_filter_t *fscan = r->filters;
+                while (!INSERT_BEFORE(f, fscan->next))
+                    fscan = fscan->next;
+                f->next = fscan->next;
+                fscan->next = f;
+            }
+
+            break;
+        }
+    }
+}
+