]> granicus.if.org Git - apache/blob - server/util_filter.c
Filters (and thus ap_pass_brigade()) now return an apr_status_t as their
[apache] / server / util_filter.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  */
54
55 #include "httpd.h"
56 #include "util_filter.h"
57
58 /*
59  * ap_filter_rec_t:
60  *
61  * This (internal) structure is used for recording information about the
62  * registered filters. It associates a name with the filter's callback
63  * and filter type.
64  *
65  * At the moment, these are simply linked in a chain, so a ->next pointer
66  * is available.
67  */
68 typedef struct ap_filter_rec_t {
69     const char *name;
70     ap_filter_func filter_func;
71     ap_filter_type ftype;
72
73     struct ap_filter_rec_t *next;
74 } ap_filter_rec_t;
75
76 /* ### make this visible for direct manipulation?
77  * ### use a hash table
78  */
79 static ap_filter_rec_t *registered_filters = NULL;
80
81 /* NOTE: Apache's current design doesn't allow a pool to be passed thu,
82    so we depend on a global to hold the correct pool
83 */
84 #define FILTER_POOL     ap_global_hook_pool
85 #include "ap_hooks.h"   /* for ap_global_hook_pool */
86
87 /*
88 ** This macro returns true/false if a given filter should be inserted BEFORE
89 ** another filter. This will happen when one of: 1) there isn't another
90 ** filter; 2) that filter has a higher filter type (class); 3) that filter
91 ** corresponds to a different request.
92 */
93 #define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
94                                        || (before_this)->ftype > (f)->ftype \
95                                        || (before_this)->r != (f)->r)
96
97
98 static apr_status_t filter_cleanup(void *ctx)
99 {
100     registered_filters = NULL;
101     return APR_SUCCESS;
102 }
103
104 API_EXPORT(void) ap_register_filter(const char *name,
105                                     ap_filter_func filter_func,
106                                     ap_filter_type ftype)
107 {
108     ap_filter_rec_t *frec = apr_palloc(FILTER_POOL, sizeof(*frec));
109
110     frec->name = name;
111     frec->filter_func = filter_func;
112     frec->ftype = ftype;
113
114     frec->next = registered_filters;
115     registered_filters = frec;
116
117     apr_register_cleanup(FILTER_POOL, NULL, filter_cleanup, apr_null_cleanup);
118 }
119
120 API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
121 {
122     ap_filter_rec_t *frec = registered_filters;
123
124     for (; frec != NULL; frec = frec->next) {
125         if (!strcasecmp(name, frec->name)) {
126             ap_filter_t *f = apr_pcalloc(r->pool, sizeof(*f));
127
128             f->filter_func = frec->filter_func;
129             f->ctx = ctx;
130             f->ftype = frec->ftype;
131             f->r = r;
132
133             if (INSERT_BEFORE(f, r->filters)) {
134                 f->next = r->filters;
135                 r->filters = f;
136             }
137             else {
138                 ap_filter_t *fscan = r->filters;
139                 while (!INSERT_BEFORE(f, fscan->next))
140                     fscan = fscan->next;
141                 f->next = fscan->next;
142                 fscan->next = f;
143             }
144
145             break;
146         }
147     }
148 }
149
150 /* Pass the buckets to the next filter in the filter stack.  If the
151  * current filter is a handler, we should get NULL passed in instead of
152  * the current filter.  At that point, we can just call the first filter in
153  * the stack, or r->filters.
154  */
155 API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
156 {
157     if (next) {
158         return next->filter_func(next, bb);
159     }
160     return AP_NOBODY_WROTE;
161 }
162
163 API_EXPORT(ap_bucket_brigade *) ap_get_saved_data(ap_filter_t *f, 
164                                                   ap_bucket_brigade **b)
165 {
166     ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
167
168     /* If we have never stored any data in the filter, then we had better
169      * create an empty bucket brigade so that we can concat.
170      */
171     if (!bb) {
172         bb = ap_brigade_create(f->r->pool);
173     }
174
175     /* join the two brigades together.  *b is now empty so we can 
176      * safely destroy it. 
177      */
178     ap_brigade_catenate(bb, *b);
179     ap_brigade_destroy(*b);
180     /* clear out the filter's context pointer.  If we don't do this, then
181      * when we save more data to the filter, we will be appended to what is
182      * currently there.  This will mean repeating data.... BAD!  :-)
183      */
184     f->ctx = NULL;
185     
186     return bb;
187 }
188
189 API_EXPORT(void) ap_save_data_to_filter(ap_filter_t *f, ap_bucket_brigade **b)
190 {
191     ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
192     ap_bucket *dptr = bb->head;
193
194     /* If have never stored any data in the filter, then we had better
195      * create an empty bucket brigade so that we can concat.
196      */
197     if (!bb) {
198         bb = ap_brigade_create(f->r->pool);
199     }
200     
201     while (dptr) {
202         if (dptr->setaside) {
203             dptr->setaside(dptr);
204         }
205     }
206
207     /* Apend b to bb.  This means b is now empty, and we can destory it safely. 
208      */
209     ap_brigade_catenate(bb, *b);
210     ap_brigade_destroy(*b);
211     f->ctx = bb;
212 }