util_filter.c revision c4f8ee4c431e4ed7119c1ea0f73e9e04e025637c
0066eddda7203f6345b56f77d146a759298dc635gryzor/* ====================================================================
0066eddda7203f6345b56f77d146a759298dc635gryzor * The Apache Software License, Version 1.1
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd *
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Copyright (c) 2000 The Apache Software Foundation. All rights
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * reserved.
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * Redistribution and use in source and binary forms, with or without
0066eddda7203f6345b56f77d146a759298dc635gryzor * modification, are permitted provided that the following conditions
0066eddda7203f6345b56f77d146a759298dc635gryzor * are met:
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc *
0066eddda7203f6345b56f77d146a759298dc635gryzor * 1. Redistributions of source code must retain the above copyright
0066eddda7203f6345b56f77d146a759298dc635gryzor * notice, this list of conditions and the following disclaimer.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen *
2e545ce2450a9953665f701bb05350f0d3f26275nd * 2. Redistributions in binary form must reproduce the above copyright
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * notice, this list of conditions and the following disclaimer in
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * the documentation and/or other materials provided with the
0066eddda7203f6345b56f77d146a759298dc635gryzor * distribution.
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * 3. The end-user documentation included with the redistribution,
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * if any, must include the following acknowledgment:
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * "This product includes software developed by the
0066eddda7203f6345b56f77d146a759298dc635gryzor * Apache Software Foundation (http://www.apache.org/)."
0066eddda7203f6345b56f77d146a759298dc635gryzor * Alternately, this acknowledgment may appear in the software itself,
0066eddda7203f6345b56f77d146a759298dc635gryzor * if and wherever such third-party acknowledgments normally appear.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd *
0066eddda7203f6345b56f77d146a759298dc635gryzor * 4. The names "Apache" and "Apache Software Foundation" must
0066eddda7203f6345b56f77d146a759298dc635gryzor * not be used to endorse or promote products derived from this
0066eddda7203f6345b56f77d146a759298dc635gryzor * software without prior written permission. For written
0066eddda7203f6345b56f77d146a759298dc635gryzor * permission, please contact apache@apache.org.
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * 5. Products derived from this software may not be called "Apache",
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * nor may "Apache" appear in their name, without prior written
0066eddda7203f6345b56f77d146a759298dc635gryzor * permission of the Apache Software Foundation.
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0066eddda7203f6345b56f77d146a759298dc635gryzor * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0066eddda7203f6345b56f77d146a759298dc635gryzor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0066eddda7203f6345b56f77d146a759298dc635gryzor * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0066eddda7203f6345b56f77d146a759298dc635gryzor * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0066eddda7203f6345b56f77d146a759298dc635gryzor * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0066eddda7203f6345b56f77d146a759298dc635gryzor * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0066eddda7203f6345b56f77d146a759298dc635gryzor * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0066eddda7203f6345b56f77d146a759298dc635gryzor * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
853ab6827637acc5cdd976cd2ea20a18f82ae184lgentis * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4aa603e6448b99f9371397d439795c91a93637eand * SUCH DAMAGE.
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh * ====================================================================
0066eddda7203f6345b56f77d146a759298dc635gryzor *
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf * This software consists of voluntary contributions made by many
0066eddda7203f6345b56f77d146a759298dc635gryzor * individuals on behalf of the Apache Software Foundation. For more
0066eddda7203f6345b56f77d146a759298dc635gryzor * information on the Apache Software Foundation, please see
0066eddda7203f6345b56f77d146a759298dc635gryzor * <http://www.apache.org/>.
853ab6827637acc5cdd976cd2ea20a18f82ae184lgentis */
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh#include "httpd.h"
4aa603e6448b99f9371397d439795c91a93637eand#include "util_filter.h"
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh
0066eddda7203f6345b56f77d146a759298dc635gryzor/*
0066eddda7203f6345b56f77d146a759298dc635gryzor * ap_filter_rec_t:
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * This (internal) structure is used for recording information about the
0066eddda7203f6345b56f77d146a759298dc635gryzor * registered filters. It associates a name with the filter's callback
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * and filter type.
0066eddda7203f6345b56f77d146a759298dc635gryzor *
0066eddda7203f6345b56f77d146a759298dc635gryzor * At the moment, these are simply linked in a chain, so a ->next pointer
0066eddda7203f6345b56f77d146a759298dc635gryzor * is available.
764f77465841302c4fb205a035754fc8398dcf1frbowen */
0066eddda7203f6345b56f77d146a759298dc635gryzortypedef struct ap_filter_rec_t {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *name;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ap_filter_func filter_func;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ap_filter_type ftype;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar struct ap_filter_rec_t *next;
564ee5b847469eb8a61120179ce70a0213965785rbowen} ap_filter_rec_t;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor/* ### make this visible for direct manipulation?
0066eddda7203f6345b56f77d146a759298dc635gryzor * ### use a hash table
0066eddda7203f6345b56f77d146a759298dc635gryzor */
0066eddda7203f6345b56f77d146a759298dc635gryzorstatic ap_filter_rec_t *registered_filters = NULL;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor/* NOTE: Apache's current design doesn't allow a pool to be passed thu,
0066eddda7203f6345b56f77d146a759298dc635gryzor so we depend on a global to hold the correct pool
0066eddda7203f6345b56f77d146a759298dc635gryzor*/
0066eddda7203f6345b56f77d146a759298dc635gryzor#define FILTER_POOL ap_global_hook_pool
0066eddda7203f6345b56f77d146a759298dc635gryzor#include "ap_hooks.h" /* for ap_global_hook_pool */
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor/*
0066eddda7203f6345b56f77d146a759298dc635gryzor** This macro returns true/false if a given filter should be inserted BEFORE
0066eddda7203f6345b56f77d146a759298dc635gryzor** another filter. This will happen when one of: 1) there isn't another
0066eddda7203f6345b56f77d146a759298dc635gryzor** filter; 2) that filter has a higher filter type (class); 3) that filter
0066eddda7203f6345b56f77d146a759298dc635gryzor** corresponds to a different request.
0066eddda7203f6345b56f77d146a759298dc635gryzor*/
0066eddda7203f6345b56f77d146a759298dc635gryzor#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
0066eddda7203f6345b56f77d146a759298dc635gryzor || (before_this)->ftype > (f)->ftype \
853ab6827637acc5cdd976cd2ea20a18f82ae184lgentis || (before_this)->r != (f)->r)
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedoohstatic apr_status_t filter_cleanup(void *ctx)
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh{
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh registered_filters = NULL;
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh return APR_SUCCESS;
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedooh}
4aa603e6448b99f9371397d439795c91a93637eand
fe2be2903c65e2f99f04199655ea5f97a75825d0humbedoohAPI_EXPORT(void) ap_register_filter(const char *name,
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_filter_func filter_func,
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_filter_type ftype)
0066eddda7203f6345b56f77d146a759298dc635gryzor{
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_filter_rec_t *frec = apr_palloc(FILTER_POOL, sizeof(*frec));
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor frec->name = name;
0066eddda7203f6345b56f77d146a759298dc635gryzor frec->filter_func = filter_func;
0066eddda7203f6345b56f77d146a759298dc635gryzor frec->ftype = ftype;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor frec->next = registered_filters;
0066eddda7203f6345b56f77d146a759298dc635gryzor registered_filters = frec;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor apr_register_cleanup(FILTER_POOL, NULL, filter_cleanup, apr_null_cleanup);
0066eddda7203f6345b56f77d146a759298dc635gryzor}
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzorAPI_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
0066eddda7203f6345b56f77d146a759298dc635gryzor{
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_filter_rec_t *frec = registered_filters;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor for (; frec != NULL; frec = frec->next) {
0066eddda7203f6345b56f77d146a759298dc635gryzor if (!strcasecmp(name, frec->name)) {
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_filter_t *f = apr_pcalloc(r->pool, sizeof(*f));
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor f->filter_func = frec->filter_func;
0066eddda7203f6345b56f77d146a759298dc635gryzor f->ctx = ctx;
0066eddda7203f6345b56f77d146a759298dc635gryzor f->ftype = frec->ftype;
0066eddda7203f6345b56f77d146a759298dc635gryzor f->r = r;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor if (INSERT_BEFORE(f, r->filters)) {
0066eddda7203f6345b56f77d146a759298dc635gryzor f->next = r->filters;
0066eddda7203f6345b56f77d146a759298dc635gryzor r->filters = f;
764f77465841302c4fb205a035754fc8398dcf1frbowen }
764f77465841302c4fb205a035754fc8398dcf1frbowen else {
e609ac39f206eb484d7d609a6a50369b1abbe112sf ap_filter_t *fscan = r->filters;
764f77465841302c4fb205a035754fc8398dcf1frbowen while (!INSERT_BEFORE(f, fscan->next))
e609ac39f206eb484d7d609a6a50369b1abbe112sf fscan = fscan->next;
e609ac39f206eb484d7d609a6a50369b1abbe112sf f->next = fscan->next;
e609ac39f206eb484d7d609a6a50369b1abbe112sf fscan->next = f;
e609ac39f206eb484d7d609a6a50369b1abbe112sf }
e609ac39f206eb484d7d609a6a50369b1abbe112sf
e609ac39f206eb484d7d609a6a50369b1abbe112sf break;
e609ac39f206eb484d7d609a6a50369b1abbe112sf }
e609ac39f206eb484d7d609a6a50369b1abbe112sf }
e609ac39f206eb484d7d609a6a50369b1abbe112sf}
e609ac39f206eb484d7d609a6a50369b1abbe112sf
764f77465841302c4fb205a035754fc8398dcf1frbowen/* Pass the buckets to the next filter in the filter stack. If the
764f77465841302c4fb205a035754fc8398dcf1frbowen * current filter is a handler, we should get NULL passed in instead of
0066eddda7203f6345b56f77d146a759298dc635gryzor * the current filter. At that point, we can just call the first filter in
0066eddda7203f6345b56f77d146a759298dc635gryzor * the stack, or r->filters.
0066eddda7203f6345b56f77d146a759298dc635gryzor */
0066eddda7203f6345b56f77d146a759298dc635gryzorAPI_EXPORT(int) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
0066eddda7203f6345b56f77d146a759298dc635gryzor{
0066eddda7203f6345b56f77d146a759298dc635gryzor if (next) {
0066eddda7203f6345b56f77d146a759298dc635gryzor return next->filter_func(next, bb);
0066eddda7203f6345b56f77d146a759298dc635gryzor }
0066eddda7203f6345b56f77d146a759298dc635gryzor return AP_NOBODY_WROTE;
0066eddda7203f6345b56f77d146a759298dc635gryzor}
0066eddda7203f6345b56f77d146a759298dc635gryzor
d5f93073383d85ebb0e4b77ae5bff13551a45dd9ndAPI_EXPORT(ap_bucket_brigade *) ap_get_saved_data(ap_filter_t *f,
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd ap_bucket_brigade **b)
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd{
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor /* If we have never stored any data in the filter, then we had better
0066eddda7203f6345b56f77d146a759298dc635gryzor * create an empty bucket brigade so that we can concat.
0066eddda7203f6345b56f77d146a759298dc635gryzor */
0066eddda7203f6345b56f77d146a759298dc635gryzor if (!bb) {
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd bb = ap_brigade_create(f->r->pool);
0066eddda7203f6345b56f77d146a759298dc635gryzor }
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd
d5f93073383d85ebb0e4b77ae5bff13551a45dd9nd /* join the two brigades together. *b is now empty so we can
0066eddda7203f6345b56f77d146a759298dc635gryzor * safely destroy it.
0066eddda7203f6345b56f77d146a759298dc635gryzor */
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_brigade_catenate(bb, *b);
0066eddda7203f6345b56f77d146a759298dc635gryzor ap_brigade_destroy(*b);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* clear out the filter's context pointer. If we don't do this, then
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * when we save more data to the filter, we will be appended to what is
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * currently there. This will mean repeating data.... BAD! :-)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar f->ctx = NULL;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return bb;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarAPI_EXPORT(void) ap_save_data_to_filter(ap_filter_t *f, ap_bucket_brigade **b)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ap_bucket *dptr = bb->head;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* If have never stored any data in the filter, then we had better
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * create an empty bucket brigade so that we can concat.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (!bb) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar bb = ap_brigade_create(f->r->pool);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
0066eddda7203f6345b56f77d146a759298dc635gryzor
0066eddda7203f6345b56f77d146a759298dc635gryzor while (dptr) {
0066eddda7203f6345b56f77d146a759298dc635gryzor if (dptr->setaside) {
0066eddda7203f6345b56f77d146a759298dc635gryzor dptr->setaside(dptr);
0066eddda7203f6345b56f77d146a759298dc635gryzor }
0066eddda7203f6345b56f77d146a759298dc635gryzor }
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung
727872d18412fc021f03969b8641810d8896820bhumbedooh /* Apend b to bb. This means b is now empty, and we can destory it safely.
0d0ba3a410038e179b695446bb149cce6264e0abnd */
727872d18412fc021f03969b8641810d8896820bhumbedooh ap_brigade_catenate(bb, *b);
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh ap_brigade_destroy(*b);
0d0ba3a410038e179b695446bb149cce6264e0abnd f->ctx = bb;
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh}
727872d18412fc021f03969b8641810d8896820bhumbedooh