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