1 /* Copyright 2000-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #define APR_WANT_STRFUNC
20 #include "apr_strings.h"
24 #include "util_filter.h"
26 /* NOTE: Apache's current design doesn't allow a pool to be passed thru,
27 so we depend on a global to hold the correct pool
29 #define FILTER_POOL apr_hook_global_pool
30 #include "apr_hooks.h" /* for apr_hook_global_pool */
33 ** This macro returns true/false if a given filter should be inserted BEFORE
34 ** another filter. This will happen when one of: 1) there isn't another
35 ** filter; 2) that filter has a higher filter type (class); 3) that filter
36 ** corresponds to a different request.
38 #define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
39 || (before_this)->frec->ftype > (f)->frec->ftype \
40 || (before_this)->r != (f)->r)
42 /* Trie structure to hold the mapping from registered
43 * filter names to filters
46 typedef struct filter_trie_node filter_trie_node;
50 filter_trie_node *child;
51 } filter_trie_child_ptr;
53 /* Each trie node has an array of pointers to its children.
54 * The array is kept in sorted order so that add_any_filter()
55 * can do a binary search
57 struct filter_trie_node {
58 ap_filter_rec_t *frec;
59 filter_trie_child_ptr *children;
64 #define TRIE_INITIAL_SIZE 4
66 /* Link a trie node to its parent
68 static void trie_node_link(apr_pool_t *p, filter_trie_node *parent,
69 filter_trie_node *child, int c)
73 if (parent->nchildren == parent->size) {
74 filter_trie_child_ptr *new;
76 new = (filter_trie_child_ptr *)apr_palloc(p, parent->size *
77 sizeof(filter_trie_child_ptr));
78 memcpy(new, parent->children, parent->nchildren *
79 sizeof(filter_trie_child_ptr));
80 parent->children = new;
83 for (i = 0; i < parent->nchildren; i++) {
84 if (c == parent->children[i].c) {
87 else if (c < parent->children[i].c) {
91 for (j = parent->nchildren; j > i; j--) {
92 parent->children[j].c = parent->children[j - 1].c;
93 parent->children[j].child = parent->children[j - 1].child;
95 parent->children[i].c = c;
96 parent->children[i].child = child;
101 /* Allocate a new node for a trie.
102 * If parent is non-NULL, link the new node under the parent node with
103 * key 'c' (or, if an existing child node matches, return that one)
105 static filter_trie_node *trie_node_alloc(apr_pool_t *p,
106 filter_trie_node *parent, char c)
108 filter_trie_node *new_node;
111 for (i = 0; i < parent->nchildren; i++) {
112 if (c == parent->children[i].c) {
113 return parent->children[i].child;
115 else if (c < parent->children[i].c) {
120 (filter_trie_node *)apr_palloc(p, sizeof(filter_trie_node));
121 trie_node_link(p, parent, new_node, c);
123 else { /* No parent node */
124 new_node = (filter_trie_node *)apr_palloc(p,
125 sizeof(filter_trie_node));
128 new_node->frec = NULL;
129 new_node->nchildren = 0;
130 new_node->size = TRIE_INITIAL_SIZE;
131 new_node->children = (filter_trie_child_ptr *)apr_palloc(p,
132 new_node->size * sizeof(filter_trie_child_ptr));
136 static filter_trie_node *registered_output_filters = NULL;
137 static filter_trie_node *registered_input_filters = NULL;
140 static apr_status_t filter_cleanup(void *ctx)
142 registered_output_filters = NULL;
143 registered_input_filters = NULL;
147 static ap_filter_rec_t *get_filter_handle(const char *name,
148 const filter_trie_node *filter_set)
152 const filter_trie_node *node;
155 for (n = name; *n; n++) {
158 end = node->nchildren - 1;
159 while (end >= start) {
160 int middle = (end + start) / 2;
161 char ch = node->children[middle].c;
163 node = node->children[middle].child;
179 if (node && node->frec) {
186 AP_DECLARE(ap_filter_rec_t *)ap_get_output_filter_handle(const char *name)
188 return get_filter_handle(name, registered_output_filters);
191 AP_DECLARE(ap_filter_rec_t *)ap_get_input_filter_handle(const char *name)
193 return get_filter_handle(name, registered_input_filters);
196 static ap_filter_rec_t *register_filter(const char *name,
197 ap_filter_func filter_func,
198 ap_init_filter_func filter_init,
199 ap_filter_type ftype,
200 filter_trie_node **reg_filter_set)
202 ap_filter_rec_t *frec;
203 char *normalized_name;
205 filter_trie_node *node;
207 if (!*reg_filter_set) {
208 *reg_filter_set = trie_node_alloc(FILTER_POOL, NULL, 0);
211 normalized_name = apr_pstrdup(FILTER_POOL, name);
212 ap_str_tolower(normalized_name);
214 node = *reg_filter_set;
215 for (n = normalized_name; *n; n++) {
216 filter_trie_node *child = trie_node_alloc(FILTER_POOL, node, *n);
217 if (apr_isalpha(*n)) {
218 trie_node_link(FILTER_POOL, node, child, apr_toupper(*n));
226 frec = apr_palloc(FILTER_POOL, sizeof(*frec));
228 frec->name = normalized_name;
230 frec->filter_func = filter_func;
231 frec->filter_init_func = filter_init;
234 apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup,
235 apr_pool_cleanup_null);
239 AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
240 ap_in_filter_func filter_func,
241 ap_init_filter_func filter_init,
242 ap_filter_type ftype)
245 f.in_func = filter_func;
246 return register_filter(name, f, filter_init, ftype,
247 ®istered_input_filters);
250 AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
251 ap_out_filter_func filter_func,
252 ap_init_filter_func filter_init,
253 ap_filter_type ftype)
256 f.out_func = filter_func;
257 return register_filter(name, f, filter_init, ftype,
258 ®istered_output_filters);
261 static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
262 request_rec *r, conn_rec *c,
263 ap_filter_t **r_filters,
264 ap_filter_t **p_filters,
265 ap_filter_t **c_filters)
267 apr_pool_t* p = r ? r->pool : c->pool;
268 ap_filter_t *f = apr_palloc(p, sizeof(*f));
271 if (frec->ftype < AP_FTYPE_PROTOCOL) {
276 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
277 "a content filter was added without a request: %s", frec->name);
281 else if (frec->ftype < AP_FTYPE_CONNECTION) {
286 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
287 "a protocol filter was added without a request: %s", frec->name);
301 if (INSERT_BEFORE(f, *outf)) {
305 ap_filter_t *first = NULL;
308 /* If we are adding our first non-connection filter,
309 * Then don't try to find the right location, it is
310 * automatically first.
312 if (*r_filters != *c_filters) {
314 while (first && (first->next != (*outf))) {
319 if (first && first != (*outf)) {
326 ap_filter_t *fscan = *outf;
327 while (!INSERT_BEFORE(f, fscan->next))
330 f->next = fscan->next;
334 if (frec->ftype < AP_FTYPE_CONNECTION && (*r_filters == *c_filters)) {
335 *r_filters = *p_filters;
340 static ap_filter_t *add_any_filter(const char *name, void *ctx,
341 request_rec *r, conn_rec *c,
342 const filter_trie_node *reg_filter_set,
343 ap_filter_t **r_filters,
344 ap_filter_t **p_filters,
345 ap_filter_t **c_filters)
347 if (reg_filter_set) {
349 const filter_trie_node *node;
351 node = reg_filter_set;
352 for (n = name; *n; n++) {
355 end = node->nchildren - 1;
356 while (end >= start) {
357 int middle = (end + start) / 2;
358 char ch = node->children[middle].c;
360 node = node->children[middle].child;
376 if (node && node->frec) {
377 return add_any_filter_handle(node->frec, ctx, r, c, r_filters,
378 p_filters, c_filters);
382 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
383 "an unknown filter was not added: %s", name);
387 AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
388 request_rec *r, conn_rec *c)
390 return add_any_filter(name, ctx, r, c, registered_input_filters,
391 r ? &r->input_filters : NULL,
392 r ? &r->proto_input_filters : NULL, &c->input_filters);
395 AP_DECLARE(ap_filter_t *) ap_add_input_filter_handle(ap_filter_rec_t *f,
400 return add_any_filter_handle(f, ctx, r, c, r ? &r->input_filters : NULL,
401 r ? &r->proto_input_filters : NULL,
405 AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx,
406 request_rec *r, conn_rec *c)
408 return add_any_filter(name, ctx, r, c, registered_output_filters,
409 r ? &r->output_filters : NULL,
410 r ? &r->proto_output_filters : NULL, &c->output_filters);
413 AP_DECLARE(ap_filter_t *) ap_add_output_filter_handle(ap_filter_rec_t *f,
418 return add_any_filter_handle(f, ctx, r, c, r ? &r->output_filters : NULL,
419 r ? &r->proto_output_filters : NULL,
423 static void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt, ap_filter_t **p_filt,
424 ap_filter_t **c_filt)
426 ap_filter_t **curr = r_filt ? r_filt : c_filt;
427 ap_filter_t *fscan = *curr;
429 if (p_filt && *p_filt == f)
430 *p_filt = (*p_filt)->next;
433 *curr = (*curr)->next;
437 while (fscan->next != f) {
438 if (!(fscan = fscan->next)) {
443 fscan->next = f->next;
446 AP_DECLARE(void) ap_remove_input_filter(ap_filter_t *f)
448 remove_any_filter(f, f->r ? &f->r->input_filters : NULL,
449 f->r ? &f->r->proto_input_filters : NULL,
450 &f->c->input_filters);
453 AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f)
455 remove_any_filter(f, f->r ? &f->r->output_filters : NULL,
456 f->r ? &f->r->proto_output_filters : NULL,
457 &f->c->output_filters);
461 * Read data from the next filter in the filter stack. Data should be
462 * modified in the bucket brigade that is passed in. The core allocates the
463 * bucket brigade, modules that wish to replace large chunks of data or to
464 * save data off to the side should probably create their own temporary
465 * brigade especially for that use.
467 AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
468 apr_bucket_brigade *bb,
469 ap_input_mode_t mode,
470 apr_read_type_e block,
474 return next->frec->filter_func.in_func(next, bb, mode, block,
477 return AP_NOBODY_READ;
480 /* Pass the buckets to the next filter in the filter stack. If the
481 * current filter is a handler, we should get NULL passed in instead of
482 * the current filter. At that point, we can just call the first filter in
483 * the stack, or r->output_filters.
485 AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next,
486 apr_bucket_brigade *bb)
490 if ((e = APR_BRIGADE_LAST(bb)) && APR_BUCKET_IS_EOS(e) && next->r) {
491 /* This is only safe because HTTP_HEADER filter is always in
492 * the filter stack. This ensures that there is ALWAYS a
493 * request-based filter that we can attach this to. If the
494 * HTTP_FILTER is removed, and another filter is not put in its
495 * place, then handlers like mod_cgi, which attach their own
496 * EOS bucket to the brigade will be broken, because we will
497 * get two EOS buckets on the same request.
499 next->r->eos_sent = 1;
501 /* remember the eos for internal redirects, too */
503 request_rec *prev = next->r->prev;
511 return next->frec->filter_func.out_func(next, bb);
513 return AP_NOBODY_WROTE;
516 AP_DECLARE(apr_status_t) ap_save_brigade(ap_filter_t *f,
517 apr_bucket_brigade **saveto,
518 apr_bucket_brigade **b, apr_pool_t *p)
523 /* If have never stored any data in the filter, then we had better
524 * create an empty bucket brigade so that we can concat.
527 *saveto = apr_brigade_create(p, f->c->bucket_alloc);
530 for (e = APR_BRIGADE_FIRST(*b);
531 e != APR_BRIGADE_SENTINEL(*b);
532 e = APR_BUCKET_NEXT(e))
534 rv = apr_bucket_setaside(e, p);
535 if (rv != APR_SUCCESS
536 /* ### this ENOTIMPL will go away once we implement setaside
537 ### for all bucket types. */
538 && rv != APR_ENOTIMPL) {
542 APR_BRIGADE_CONCAT(*saveto, *b);
546 AP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb,
549 ap_filter_t *f = ctx;
551 return ap_pass_brigade(f, bb);
554 AP_DECLARE(apr_status_t) ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
558 b = apr_bucket_flush_create(f->c->bucket_alloc);
559 APR_BRIGADE_INSERT_TAIL(bb, b);
560 return ap_pass_brigade(f, bb);
563 AP_DECLARE_NONSTD(apr_status_t) ap_fputstrs(ap_filter_t *f,
564 apr_bucket_brigade *bb, ...)
570 rv = apr_brigade_vputstrs(bb, ap_filter_flush, f, args);
575 AP_DECLARE_NONSTD(apr_status_t) ap_fprintf(ap_filter_t *f,
576 apr_bucket_brigade *bb,
584 rv = apr_brigade_vprintf(bb, ap_filter_flush, f, fmt, args);