--- /dev/null
+/* ====================================================================
+ * 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 */
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 */
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);
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;
--- /dev/null
+/* ====================================================================
+ * 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;
+ }
+ }
+}
+