util_filter.c revision 3d96ee83babeec32482c9082c9426340cee8c44d
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering/* ====================================================================
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * The Apache Software License, Version 1.1
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * Copyright (c) 2000 The Apache Software Foundation. All rights
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * reserved.
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * Redistribution and use in source and binary forms, with or without
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * modification, are permitted provided that the following conditions
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * are met:
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * 1. Redistributions of source code must retain the above copyright
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * notice, this list of conditions and the following disclaimer.
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * 2. Redistributions in binary form must reproduce the above copyright
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * notice, this list of conditions and the following disclaimer in
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * the documentation and/or other materials provided with the
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * distribution.
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * 3. The end-user documentation included with the redistribution,
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * if any, must include the following acknowledgment:
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * "This product includes software developed by the
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * Apache Software Foundation (http://www.apache.org/)."
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * Alternately, this acknowledgment may appear in the software itself,
f4ce2b3e5ce93b83f14f8785e205ebb5a9b8c1dfLennart Poettering * if and wherever such third-party acknowledgments normally appear.
a8fbdf5424be099ba1b2b1ec261c02b8759d6b0cThomas Hindoe Paaboel Andersen *
a8fbdf5424be099ba1b2b1ec261c02b8759d6b0cThomas Hindoe Paaboel Andersen * 4. The names "Apache" and "Apache Software Foundation" must
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * not be used to endorse or promote products derived from this
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * software without prior written permission. For written
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * permission, please contact apache@apache.org.
f4ce2b3e5ce93b83f14f8785e205ebb5a9b8c1dfLennart Poettering *
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * 5. Products derived from this software may not be called "Apache",
7b4d7cc08283e5485dcfa49ffdf1915de1d5e81bKay Sievers * nor may "Apache" appear in their name, without prior written
7b4d7cc08283e5485dcfa49ffdf1915de1d5e81bKay Sievers * permission of the Apache Software Foundation.
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers *
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
7b4d7cc08283e5485dcfa49ffdf1915de1d5e81bKay Sievers * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
733dbdc53425a00ac95328ef531bbfce263df5ecThomas Hindoe Paaboel Andersen * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9cde64ff264c432fc83be638e57d8fd6392793a6Lennart Poettering * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9df49b33583e8a7d0a252bc5bd532fd2448ef0c8Tom Gundersen * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
9df49b33583e8a7d0a252bc5bd532fd2448ef0c8Tom Gundersen * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5bdf22430e367799dfa66c724144b624c5479518Jan Janssen * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5bdf22430e367799dfa66c724144b624c5479518Jan Janssen * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
5bdf22430e367799dfa66c724144b624c5479518Jan Janssen * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34e5a31ec5897de8ba1436dad53df99637569d0aLennart Poettering * SUCH DAMAGE.
2e3d069236777cd62f755a02f4a239306b4ad21aLennart Poettering * ====================================================================
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers *
9cde64ff264c432fc83be638e57d8fd6392793a6Lennart Poettering * This software consists of voluntary contributions made by many
7b4d7cc08283e5485dcfa49ffdf1915de1d5e81bKay Sievers * individuals on behalf of the Apache Software Foundation. For more
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers * information on the Apache Software Foundation, please see
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers * <http://www.apache.org/>.
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers */
9cde64ff264c432fc83be638e57d8fd6392793a6Lennart Poettering
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers#include "httpd.h"
9cde64ff264c432fc83be638e57d8fd6392793a6Lennart Poettering#include "util_filter.h"
34e5a31ec5897de8ba1436dad53df99637569d0aLennart Poettering
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* ### make this visible for direct manipulation?
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * ### use a hash table
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers */
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersenstatic ap_filter_rec_t *registered_output_filters = NULL;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersenstatic ap_filter_rec_t *registered_input_filters = NULL;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen/* NOTE: Apache's current design doesn't allow a pool to be passed thu,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen so we depend on a global to hold the correct pool
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen*/
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen#define FILTER_POOL ap_global_hook_pool
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen#include "ap_hooks.h" /* for ap_global_hook_pool */
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen/*
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen** This macro returns true/false if a given filter should be inserted BEFORE
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen** another filter. This will happen when one of: 1) there isn't another
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen** filter; 2) that filter has a higher filter type (class); 3) that filter
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen** corresponds to a different request.
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen*/
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen || (before_this)->frec->ftype > (f)->frec->ftype \
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen || (before_this)->r != (f)->r)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersenstatic apr_status_t filter_cleanup(void *ctx)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen{
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen registered_output_filters = NULL;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen registered_input_filters = NULL;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen return APR_SUCCESS;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen}
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersenstatic void register_filter(const char *name,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_func filter_func,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_type ftype,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_rec_t **reg_filter_list)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen{
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_rec_t *frec = apr_palloc(FILTER_POOL, sizeof(*frec));
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen frec->name = name;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen frec->filter_func = filter_func;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen frec->ftype = ftype;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen frec->next = *reg_filter_list;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen *reg_filter_list = frec;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen apr_register_cleanup(FILTER_POOL, NULL, filter_cleanup, apr_null_cleanup);
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen}
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom GundersenAP_DECLARE(void) ap_register_input_filter(const char *name,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_in_filter_func filter_func,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_type ftype)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen{
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_func f;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen f.in_func = filter_func;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen register_filter(name, f, ftype,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen &registered_input_filters);
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen}
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom GundersenAP_DECLARE(void) ap_register_output_filter(const char *name,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_out_filter_func filter_func,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_type ftype)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen{
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_func f;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen f.out_func = filter_func;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen register_filter(name, f, ftype,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen &registered_output_filters);
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen}
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom GundersenAP_DECLARE(void) ap_add_input_filter(const char *name, void *ctx,
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen request_rec *r, conn_rec *c)
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen{
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen ap_filter_rec_t *frec = registered_input_filters;
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen for (; frec != NULL; frec = frec->next) {
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen if (!strcasecmp(name, frec->name)) {
b28ce7c6dbe341d6f5769d31014ab8411257db7dTom Gundersen apr_pool_t *p = r ? r->pool : c->pool;
0974a682d155a5874123ba7de9c1e314c6681e0fKay Sievers ap_filter_t *f = apr_pcalloc(p, sizeof(*f));
ap_filter_t **outf = r ? &r->input_filters : &c->input_filters;
f->frec = frec;
f->ctx = ctx;
f->r = r;
f->c = c;
if (INSERT_BEFORE(f, *outf)) {
f->next = *outf;
*outf = f;
}
else {
ap_filter_t *fscan = *outf;
while (!INSERT_BEFORE(f, fscan->next))
fscan = fscan->next;
f->next = fscan->next;
fscan->next = f;
}
break;
}
}
}
AP_DECLARE(void) ap_add_output_filter(const char *name, void *ctx,
request_rec *r, conn_rec *c)
{
ap_filter_rec_t *frec = registered_output_filters;
for (; frec != NULL; frec = frec->next) {
if (!strcasecmp(name, frec->name)) {
apr_pool_t *p = r ? r->pool : c->pool;
ap_filter_t *f = apr_pcalloc(p, sizeof(*f));
ap_filter_t **outf = r ? &r->output_filters : &c->output_filters;
f->frec = frec;
f->ctx = ctx;
f->r = r;
f->c = c;
if (INSERT_BEFORE(f, *outf)) {
f->next = *outf;
*outf = f;
}
else {
ap_filter_t *fscan = *outf;
while (!INSERT_BEFORE(f, fscan->next))
fscan = fscan->next;
f->next = fscan->next;
fscan->next = f;
}
break;
}
}
}
/*
* Read data from the next filter in the filter stack. Data should be
* modified in the bucket brigade that is passed in. The core allocates the
* bucket brigade, modules that wish to replace large chunks of data or to
* save data off to the side should probably create their own temporary
* brigade especially for that use.
*/
AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
ap_bucket_brigade *bb, apr_ssize_t length)
{
if (next) {
return next->frec->filter_func.in_func(next, bb, length);
}
return AP_NOBODY_READ;
}
/* Pass the buckets to the next filter in the filter stack. If the
* current filter is a handler, we should get NULL passed in instead of
* the current filter. At that point, we can just call the first filter in
* the stack, or r->output_filters.
*/
AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
{
if (next) {
ap_bucket *e;
if ((e = AP_BRIGADE_LAST(bb)) && AP_BUCKET_IS_EOS(e) && next->r) {
next->r->eos_sent = 1;
}
return next->frec->filter_func.out_func(next, bb);
}
return AP_NOBODY_WROTE;
}
AP_DECLARE(void) ap_save_brigade(ap_filter_t *f, ap_bucket_brigade **saveto,
ap_bucket_brigade **b)
{
ap_bucket *e;
apr_pool_t *p = f->r ? f->r->pool : f->c->pool;
/* If have never stored any data in the filter, then we had better
* create an empty bucket brigade so that we can concat.
*/
if (!(*saveto)) {
*saveto = ap_brigade_create(p);
}
AP_RING_FOREACH(e, &(*b)->list, ap_bucket, link) {
ap_bucket_setaside(e);
}
AP_BRIGADE_CONCAT(*saveto, *b);
}