]> granicus.if.org Git - apache/blob - server/util_filter.c
showstoppers--;
[apache] / server / util_filter.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 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 #define APR_WANT_STRFUNC
56 #include "apr_want.h"
57 #include "apr_lib.h"
58 #include "apr_hash.h"
59 #include "apr_strings.h"
60
61 #include "httpd.h"
62 #include "http_log.h"
63 #include "util_filter.h"
64
65 /* NOTE: Apache's current design doesn't allow a pool to be passed thru,
66    so we depend on a global to hold the correct pool
67 */
68 #define FILTER_POOL     apr_global_hook_pool
69 #include "apr_hooks.h"   /* for apr_global_hook_pool */
70
71 /*
72 ** This macro returns true/false if a given filter should be inserted BEFORE
73 ** another filter. This will happen when one of: 1) there isn't another
74 ** filter; 2) that filter has a higher filter type (class); 3) that filter
75 ** corresponds to a different request.
76 */
77 #define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
78                            || (before_this)->frec->ftype > (f)->frec->ftype \
79                            || (before_this)->r != (f)->r)
80
81 /* Trie structure to hold the mapping from registered
82  * filter names to filters
83  */
84
85 typedef struct filter_trie_node filter_trie_node;
86
87 typedef struct {
88     int c;
89     filter_trie_node *child;
90 } filter_trie_child_ptr;
91
92 /* Each trie node has an array of pointers to its children.
93  * The array is kept in sorted order so that add_any_filter()
94  * can do a binary search
95  */
96 struct filter_trie_node {
97     ap_filter_rec_t *frec;
98     filter_trie_child_ptr *children;
99     int nchildren;
100     int size;
101 };
102
103 #define TRIE_INITIAL_SIZE 4
104
105 /* Link a trie node to its parent
106  */
107 static void trie_node_link(apr_pool_t *p, filter_trie_node *parent,
108                            filter_trie_node *child, int c)
109 {
110     int i, j;
111
112     if (parent->nchildren == parent->size) {
113         filter_trie_child_ptr *new;
114         parent->size *= 2;
115         new = (filter_trie_child_ptr *)apr_palloc(p, parent->size *
116                                              sizeof(filter_trie_child_ptr));
117         memcpy(new, parent->children, parent->nchildren *
118                sizeof(filter_trie_child_ptr));
119         parent->children = new;
120     }
121
122     for (i = 0; i < parent->nchildren; i++) {
123         if (c == parent->children[i].c) {
124             return;
125         }
126         else if (c < parent->children[i].c) {
127             break;
128         }
129     }
130     for (j = parent->nchildren; j > i; j--) {
131         parent->children[j].c = parent->children[j - 1].c;
132         parent->children[j].child = parent->children[j - 1].child;
133     }
134     parent->children[i].c = c;
135     parent->children[i].child = child;
136
137     parent->nchildren++;
138 }
139
140 /* Allocate a new node for a trie.
141  * If parent is non-NULL, link the new node under the parent node with
142  * key 'c' (or, if an existing child node matches, return that one)
143  */
144 static filter_trie_node *trie_node_alloc(apr_pool_t *p,
145                                          filter_trie_node *parent, char c)
146 {
147     filter_trie_node *new_node;
148     if (parent) {
149         int i;
150         for (i = 0; i < parent->nchildren; i++) {
151             if (c == parent->children[i].c) {
152                 return parent->children[i].child;
153             }
154             else if (c < parent->children[i].c) {
155                 break;
156             }
157         }
158         new_node =
159             (filter_trie_node *)apr_palloc(p, sizeof(filter_trie_node));
160         trie_node_link(p, parent, new_node, c);
161     }
162     else { /* No parent node */
163         new_node = (filter_trie_node *)apr_palloc(p,
164                                                   sizeof(filter_trie_node));
165     }
166
167     new_node->frec = NULL;
168     new_node->nchildren = 0;
169     new_node->size = TRIE_INITIAL_SIZE;
170     new_node->children = (filter_trie_child_ptr *)apr_palloc(p,
171                              new_node->size * sizeof(filter_trie_child_ptr));
172     return new_node;
173 }
174
175 static filter_trie_node *registered_output_filters = NULL;
176 static filter_trie_node *registered_input_filters = NULL;
177
178
179 static apr_status_t filter_cleanup(void *ctx)
180 {
181     registered_output_filters = NULL;
182     registered_input_filters = NULL;
183     return APR_SUCCESS;
184 }
185
186 static ap_filter_rec_t *register_filter(const char *name,
187                             ap_filter_func filter_func,
188                             ap_filter_type ftype,
189                             filter_trie_node **reg_filter_set)
190 {
191     ap_filter_rec_t *frec = apr_palloc(FILTER_POOL, sizeof(*frec));
192     const char *n;
193     filter_trie_node *node;
194
195     if (!*reg_filter_set) {
196         *reg_filter_set = trie_node_alloc(FILTER_POOL, NULL, 0);
197     }
198
199     frec->name = apr_pstrdup(FILTER_POOL, name);
200     ap_str_tolower((char *)frec->name);
201     frec->filter_func = filter_func;
202     frec->ftype = ftype;
203
204     node = *reg_filter_set;
205     for (n = frec->name; *n; n++) {
206         filter_trie_node *child = trie_node_alloc(FILTER_POOL, node, *n);
207         if (apr_isalpha(*n)) {
208             trie_node_link(FILTER_POOL, node, child, apr_toupper(*n));
209         }
210         node = child;
211     }
212     node->frec = frec;
213     
214     apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup, 
215                               apr_pool_cleanup_null);
216     return frec;
217 }
218
219 AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
220                                           ap_in_filter_func filter_func,
221                                           ap_filter_type ftype)
222 {
223     ap_filter_func f;
224     f.in_func = filter_func;
225     return register_filter(name, f, ftype, &registered_input_filters);
226 }                                                                    
227
228 AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
229                                            ap_out_filter_func filter_func,
230                                            ap_filter_type ftype)
231 {
232     ap_filter_func f;
233     f.out_func = filter_func;
234     return register_filter(name, f, ftype, &registered_output_filters);
235 }
236
237 static ap_filter_t *add_any_filter(const char *name, void *ctx, 
238                                    request_rec *r, conn_rec *c, 
239                                    const filter_trie_node *reg_filter_set,
240                                    ap_filter_t **r_filters,
241                                    ap_filter_t **c_filters)
242 {
243     if (reg_filter_set) {
244         const char *n;
245         const filter_trie_node *node;
246
247         node = reg_filter_set;
248         for (n = name; *n; n++) {
249             int start, end;
250             start = 0;
251             end = node->nchildren - 1;
252             while (end >= start) {
253                 int middle = (end + start) / 2;
254                 char ch = node->children[middle].c;
255                 if (*n == ch) {
256                     node = node->children[middle].child;
257                     break;
258                 }
259                 else if (*n < ch) {
260                     end = middle - 1;
261                 }
262                 else {
263                     start = middle + 1;
264                 }
265             }
266             if (end < start) {
267                 node = NULL;
268                 break;
269             }
270         }
271
272         if (node && node->frec) {
273             apr_pool_t* p = r ? r->pool : c->pool;
274             ap_filter_t *f = apr_palloc(p, sizeof(*f));
275             ap_filter_t **outf = r ? r_filters : c_filters;
276
277             f->frec = node->frec;
278             f->ctx = ctx;
279             f->r = r;
280             f->c = c;
281
282             if (INSERT_BEFORE(f, *outf)) {
283                 f->next = *outf;
284                 *outf = f;
285             }
286             else {
287                 ap_filter_t *fscan = *outf;
288                 while (!INSERT_BEFORE(f, fscan->next))
289                     fscan = fscan->next;
290                 f->next = fscan->next;
291                 fscan->next = f;
292             }
293
294             return f;
295         }
296     }
297
298     ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
299                  "an unknown filter was not added: %s", name);
300     return NULL;
301 }
302
303 AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
304                                               request_rec *r, conn_rec *c)
305 {
306     return add_any_filter(name, ctx, r, c, registered_input_filters,
307                           r ? &r->input_filters : NULL, &c->input_filters);
308 }
309
310 AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx,
311                                                request_rec *r, conn_rec *c)
312 {
313     return add_any_filter(name, ctx, r, c, registered_output_filters,
314                           r ? &r->output_filters : NULL, &c->output_filters);
315 }
316
317 static void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt, 
318                               ap_filter_t **c_filt)
319 {
320     ap_filter_t **curr = r_filt ? r_filt : c_filt;
321     ap_filter_t *fscan = *curr;
322
323     if (*curr == f) {
324         *curr = (*curr)->next;
325         return;
326     }
327
328     while (fscan->next != f) {
329         if (!(fscan = fscan->next)) {
330             return;
331         }
332     }
333
334     fscan->next = f->next;
335 }
336
337 AP_DECLARE(void) ap_remove_input_filter(ap_filter_t *f)
338 {
339     remove_any_filter(f, f->r ? &f->r->input_filters : NULL, 
340                       &f->c->input_filters);
341 }
342
343 AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f)
344 {
345     remove_any_filter(f, f->r ? &f->r->output_filters : NULL, 
346                       &f->c->output_filters);
347 }
348
349 /* 
350  * Read data from the next filter in the filter stack.  Data should be 
351  * modified in the bucket brigade that is passed in.  The core allocates the
352  * bucket brigade, modules that wish to replace large chunks of data or to
353  * save data off to the side should probably create their own temporary
354  * brigade especially for that use.
355  */
356 AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
357                                         apr_bucket_brigade *bb, 
358                                         ap_input_mode_t mode,
359                                         apr_off_t *readbytes)
360 {
361     if (next) {
362         return next->frec->filter_func.in_func(next, bb, mode, readbytes);
363     }
364     return AP_NOBODY_READ;
365 }
366
367 /* Pass the buckets to the next filter in the filter stack.  If the
368  * current filter is a handler, we should get NULL passed in instead of
369  * the current filter.  At that point, we can just call the first filter in
370  * the stack, or r->output_filters.
371  */
372 AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next, 
373                                          apr_bucket_brigade *bb)
374 {
375     if (next) {
376         apr_bucket *e;
377         if ((e = APR_BRIGADE_LAST(bb)) && APR_BUCKET_IS_EOS(e) && next->r) {
378             /* This is only safe because HTTP_HEADER filter is always in
379              * the filter stack.   This ensures that there is ALWAYS a
380              * request-based filter that we can attach this to.  If the
381              * HTTP_FILTER is removed, and another filter is not put in its
382              * place, then handlers like mod_cgi, which attach their own
383              * EOS bucket to the brigade will be broken, because we will
384              * get two EOS buckets on the same request.
385              */
386             next->r->eos_sent = 1;
387         }
388         return next->frec->filter_func.out_func(next, bb);
389     }
390     return AP_NOBODY_WROTE;
391 }
392
393 AP_DECLARE(apr_status_t) ap_save_brigade(ap_filter_t *f, 
394                                          apr_bucket_brigade **saveto,
395                                          apr_bucket_brigade **b, apr_pool_t *p)
396 {
397     apr_bucket *e;
398     apr_status_t rv;
399
400     /* If have never stored any data in the filter, then we had better
401      * create an empty bucket brigade so that we can concat.
402      */
403     if (!(*saveto)) {
404         *saveto = apr_brigade_create(p);
405     }
406     
407     APR_RING_FOREACH(e, &(*b)->list, apr_bucket, link) {
408         rv = apr_bucket_setaside(e, p);
409         if (rv != APR_SUCCESS
410             /* ### this ENOTIMPL will go away once we implement setaside
411                ### for all bucket types. */
412             && rv != APR_ENOTIMPL) {
413             return rv;
414         }
415     }
416     APR_BRIGADE_CONCAT(*saveto, *b);
417     return APR_SUCCESS;
418 }
419
420 AP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb, 
421                                                 void *ctx)
422 {
423     ap_filter_t *f = ctx;
424
425     return ap_pass_brigade(f, bb);
426 }
427
428 AP_DECLARE(apr_status_t) ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
429 {
430     apr_bucket *b;
431
432     b = apr_bucket_flush_create();
433     APR_BRIGADE_INSERT_TAIL(bb, b);
434     return ap_pass_brigade(f, bb);
435 }
436
437 AP_DECLARE_NONSTD(apr_status_t) ap_fputstrs(ap_filter_t *f,
438                                             apr_bucket_brigade *bb, ...)
439 {
440     va_list args;
441     apr_status_t rv;
442
443     va_start(args, bb);
444     rv = apr_brigade_vputstrs(bb, ap_filter_flush, f, args);
445     va_end(args);
446     return rv;
447 }
448
449 AP_DECLARE_NONSTD(apr_status_t) ap_fprintf(ap_filter_t *f,
450                                            apr_bucket_brigade *bb,
451                                            const char *fmt,
452                                            ...)
453 {
454     va_list args;
455     apr_status_t rv;
456
457     va_start(args, fmt);
458     rv = apr_brigade_vprintf(bb, ap_filter_flush, f, fmt, args);
459     va_end(args);
460     return rv;
461 }