mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Add the ability to register filters. This commit introduces a warning
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
This commit is contained in:
@@ -732,6 +732,8 @@ struct request_rec {
|
||||
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
|
||||
|
220
include/util_filter.h
Normal file
220
include/util_filter.h
Normal file
@@ -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 */
|
@@ -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
|
||||
|
@@ -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)
|
||||
{
|
||||
#ifndef APACHE_XLATE
|
||||
int retval = ap_invoke_handler(r);
|
||||
#else /*APACHE_XLATE*/
|
||||
/* Save the output conversion setting of the caller across subrequests */
|
||||
int retval;
|
||||
|
||||
/* see comments in process_request_internal() */
|
||||
ap_run_insert_filter(r);
|
||||
|
||||
#ifndef APACHE_XLATE
|
||||
retval = ap_invoke_handler(r);
|
||||
#else /*APACHE_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);
|
||||
}
|
||||
#endif /*APACHE_XLATE*/
|
||||
ap_finalize_sub_req_protocol(r);
|
||||
return retval;
|
||||
|
@@ -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
|
||||
|
||||
|
146
server/util_filter.c
Normal file
146
server/util_filter.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user