Apache HTTPD
util_filter.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define APR_WANT_STRFUNC
18#include "apr_want.h"
19#include "apr_lib.h"
20#include "apr_hash.h"
21#include "apr_strings.h"
22
23#include "httpd.h"
24#include "http_config.h"
25#include "http_core.h"
26#include "http_log.h"
27#include "util_filter.h"
28
29/* NOTE: Apache's current design doesn't allow a pool to be passed thru,
30 so we depend on a global to hold the correct pool
31*/
32#define FILTER_POOL apr_hook_global_pool
33#include "ap_hooks.h" /* for apr_hook_global_pool */
34
35/*
36** This macro returns true/false if a given filter should be inserted BEFORE
37** another filter. This will happen when one of: 1) there isn't another
38** filter; 2) that filter has a higher filter type (class); 3) that filter
39** corresponds to a different request.
40*/
41#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
42 || (before_this)->frec->ftype > (f)->frec->ftype \
43 || (before_this)->r != (f)->r)
44
45/* Trie structure to hold the mapping from registered
46 * filter names to filters
47 */
48
49/* we know core's module_index is 0 */
50#undef APLOG_MODULE_INDEX
51#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
52
54
59
60/* Each trie node has an array of pointers to its children.
61 * The array is kept in sorted order so that add_any_filter()
62 * can do a binary search
63 */
70
71#define TRIE_INITIAL_SIZE 4
72
73/* Link a trie node to its parent
74 */
76 filter_trie_node *child, int c)
77{
78 int i, j;
79
80 if (parent->nchildren == parent->size) {
82 parent->size *= 2;
84 sizeof(filter_trie_child_ptr));
85 memcpy(new, parent->children, parent->nchildren *
86 sizeof(filter_trie_child_ptr));
87 parent->children = new;
88 }
89
90 for (i = 0; i < parent->nchildren; i++) {
91 if (c == parent->children[i].c) {
92 return;
93 }
94 else if (c < parent->children[i].c) {
95 break;
96 }
97 }
98 for (j = parent->nchildren; j > i; j--) {
99 parent->children[j].c = parent->children[j - 1].c;
100 parent->children[j].child = parent->children[j - 1].child;
101 }
102 parent->children[i].c = c;
103 parent->children[i].child = child;
104
105 parent->nchildren++;
106}
107
108/* Allocate a new node for a trie.
109 * If parent is non-NULL, link the new node under the parent node with
110 * key 'c' (or, if an existing child node matches, return that one)
111 */
114{
116 if (parent) {
117 int i;
118 for (i = 0; i < parent->nchildren; i++) {
119 if (c == parent->children[i].c) {
120 return parent->children[i].child;
121 }
122 else if (c < parent->children[i].c) {
123 break;
124 }
125 }
126 new_node =
129 }
130 else { /* No parent node */
132 sizeof(filter_trie_node));
133 }
134
135 new_node->frec = NULL;
136 new_node->nchildren = 0;
139 new_node->size * sizeof(filter_trie_child_ptr));
140 return new_node;
141}
142
145
146
153
156{
157 if (filter_set) {
158 const char *n;
159 const filter_trie_node *node;
160
161 node = filter_set;
162 for (n = name; *n; n++) {
163 int start, end;
164 start = 0;
165 end = node->nchildren - 1;
166 while (end >= start) {
167 int middle = (end + start) / 2;
168 char ch = node->children[middle].c;
169 if (*n == ch) {
170 node = node->children[middle].child;
171 break;
172 }
173 else if (*n < ch) {
174 end = middle - 1;
175 }
176 else {
177 start = middle + 1;
178 }
179 }
180 if (end < start) {
181 node = NULL;
182 break;
183 }
184 }
185
186 if (node && node->frec) {
187 return node->frec;
188 }
189 }
190 return NULL;
191}
192
197
202
204 ap_filter_func filter_func,
206 ap_filter_type ftype,
208{
209 ap_filter_rec_t *frec;
210 char *normalized_name;
211 const char *n;
212 filter_trie_node *node;
213
214 if (!*reg_filter_set) {
216 }
217
220
221 node = *reg_filter_set;
222 for (n = normalized_name; *n; n++) {
224 if (apr_isalpha(*n)) {
225 trie_node_link(FILTER_POOL, node, child, apr_toupper(*n));
226 }
227 node = child;
228 }
229 if (node->frec) {
230 frec = node->frec;
231 }
232 else {
233 frec = apr_pcalloc(FILTER_POOL, sizeof(*frec));
234 node->frec = frec;
235 frec->name = normalized_name;
236 }
237 frec->filter_func = filter_func;
239 frec->ftype = ftype;
240
243 return frec;
244}
245
247 ap_in_filter_func filter_func,
249 ap_filter_type ftype)
250{
252 f.in_func = filter_func;
253 return register_filter(name, f, filter_init, ftype,
255}
256
265
267 const char *name,
268 ap_out_filter_func filter_func,
270 ap_filter_type ftype,
271 unsigned int proto_flags)
272{
275 f.out_func = filter_func;
278 ret->proto_flags = proto_flags ;
279 return ret ;
280}
281
287{
288 apr_pool_t *p = frec->ftype < AP_FTYPE_CONNECTION && r ? r->pool : c->pool;
289 ap_filter_t *f = apr_palloc(p, sizeof(*f));
291
292 if (frec->ftype < AP_FTYPE_PROTOCOL) {
293 if (r) {
294 outf = r_filters;
295 }
296 else {
298 "a content filter was added without a request: %s", frec->name);
299 return NULL;
300 }
301 }
302 else if (frec->ftype < AP_FTYPE_CONNECTION) {
303 if (r) {
304 outf = p_filters;
305 }
306 else {
308 "a protocol filter was added without a request: %s", frec->name);
309 return NULL;
310 }
311 }
312 else {
313 outf = c_filters;
314 }
315
316 f->frec = frec;
317 f->ctx = ctx;
318 /* f->r must always be NULL for connection filters */
319 f->r = frec->ftype < AP_FTYPE_CONNECTION ? r : NULL;
320 f->c = c;
321 f->next = NULL;
322
323 if (INSERT_BEFORE(f, *outf)) {
324 f->next = *outf;
325
326 if (*outf) {
328
329 if (r) {
330 /* If we are adding our first non-connection filter,
331 * Then don't try to find the right location, it is
332 * automatically first.
333 */
334 if (*r_filters != *c_filters) {
335 first = *r_filters;
336 while (first && (first->next != (*outf))) {
337 first = first->next;
338 }
339 }
340 }
341 if (first && first != (*outf)) {
342 first->next = f;
343 }
344 }
345 *outf = f;
346 }
347 else {
349 while (!INSERT_BEFORE(f, fscan->next))
350 fscan = fscan->next;
351
352 f->next = fscan->next;
353 fscan->next = f;
354 }
355
356 if (frec->ftype < AP_FTYPE_CONNECTION && (*r_filters == *c_filters)) {
358 }
359 return f;
360}
361
362static ap_filter_t *add_any_filter(const char *name, void *ctx,
368{
369 if (reg_filter_set) {
370 const char *n;
371 const filter_trie_node *node;
372
373 node = reg_filter_set;
374 for (n = name; *n; n++) {
375 int start, end;
376 start = 0;
377 end = node->nchildren - 1;
378 while (end >= start) {
379 int middle = (end + start) / 2;
380 char ch = node->children[middle].c;
381 if (*n == ch) {
382 node = node->children[middle].child;
383 break;
384 }
385 else if (*n < ch) {
386 end = middle - 1;
387 }
388 else {
389 start = middle + 1;
390 }
391 }
392 if (end < start) {
393 node = NULL;
394 break;
395 }
396 }
397
398 if (node && node->frec) {
399 return add_any_filter_handle(node->frec, ctx, r, c, r_filters,
401 }
402 }
403
405 "an unknown filter was not added: %s", name);
406 return NULL;
407}
408
411{
413 r ? &r->input_filters : NULL,
414 r ? &r->proto_input_filters : NULL, &c->input_filters);
415}
416
418 void *ctx,
419 request_rec *r,
420 conn_rec *c)
421{
422 return add_any_filter_handle(f, ctx, r, c, r ? &r->input_filters : NULL,
424 &c->input_filters);
425}
426
429{
431 r ? &r->output_filters : NULL,
432 r ? &r->proto_output_filters : NULL, &c->output_filters);
433}
434
436 void *ctx,
437 request_rec *r,
438 conn_rec *c)
439{
442 &c->output_filters);
443}
444
447{
450
451 if (p_filt && *p_filt == f)
452 *p_filt = (*p_filt)->next;
453
454 if (*curr == f) {
455 *curr = (*curr)->next;
456 return;
457 }
458
459 while (fscan->next != f) {
460 if (!(fscan = fscan->next)) {
461 return;
462 }
463 }
464
465 fscan->next = f->next;
466}
467
469{
470 remove_any_filter(f, f->r ? &f->r->input_filters : NULL,
471 f->r ? &f->r->proto_input_filters : NULL,
472 &f->c->input_filters);
473}
474
476{
477 remove_any_filter(f, f->r ? &f->r->output_filters : NULL,
478 f->r ? &f->r->proto_output_filters : NULL,
479 &f->c->output_filters);
480}
481
483 const char *handle)
484{
486 ap_filter_rec_t *filter;
487
488 if (!handle) {
489 return APR_EINVAL;
490 }
492 if (!filter) {
493 return APR_NOTFOUND;
494 }
495
496 while (next) {
497 if (next->frec == filter) {
498 found = next;
499 break;
500 }
501 next = next->next;
502 }
503 if (found) {
505 return APR_SUCCESS;
506 }
507 return APR_NOTFOUND;
508}
509
511 const char *handle)
512{
514 ap_filter_rec_t *filter;
515
516 if (!handle) {
517 return APR_EINVAL;
518 }
520 if (!filter) {
521 return APR_NOTFOUND;
522 }
523
524 while (next) {
525 if (next->frec == filter) {
526 found = next;
527 break;
528 }
529 next = next->next;
530 }
531 if (found) {
533 return APR_SUCCESS;
534 }
535 return APR_NOTFOUND;
536}
537
538
539/*
540 * Read data from the next filter in the filter stack. Data should be
541 * modified in the bucket brigade that is passed in. The core allocates the
542 * bucket brigade, modules that wish to replace large chunks of data or to
543 * save data off to the side should probably create their own temporary
544 * brigade especially for that use.
545 */
551{
552 if (next) {
553 return next->frec->filter_func.in_func(next, bb, mode, block,
554 readbytes);
555 }
556 return AP_NOBODY_READ;
557}
558
559/* Pass the buckets to the next filter in the filter stack. If the
560 * current filter is a handler, we should get NULL passed in instead of
561 * the current filter. At that point, we can just call the first filter in
562 * the stack, or r->output_filters.
563 */
566{
567 if (next) {
569
570 if (e != APR_BRIGADE_SENTINEL(bb) && APR_BUCKET_IS_EOS(e) && next->r) {
571 /* This is only safe because HTTP_HEADER filter is always in
572 * the filter stack. This ensures that there is ALWAYS a
573 * request-based filter that we can attach this to. If the
574 * HTTP_FILTER is removed, and another filter is not put in its
575 * place, then handlers like mod_cgi, which attach their own
576 * EOS bucket to the brigade will be broken, because we will
577 * get two EOS buckets on the same request.
578 */
579 next->r->eos_sent = 1;
580
581 /* remember the eos for internal redirects, too */
582 if (next->r->prev) {
583 request_rec *prev = next->r->prev;
584
585 while (prev) {
586 prev->eos_sent = 1;
587 prev = prev->prev;
588 }
589 }
590 }
591 return next->frec->filter_func.out_func(next, bb);
592 }
593 return AP_NOBODY_WROTE;
594}
595
596/* Pass the buckets to the next filter in the filter stack
597 * checking return status for filter errors.
598 * returns: OK if ap_pass_brigade returns APR_SUCCESS
599 * AP_FILTER_ERROR if filter error exists
600 * HTTP_INTERNAL_SERVER_ERROR for all other cases
601 * logged with optional errmsg
602 */
605 const char *fmt,
606 ...)
607{
608 apr_status_t rv;
609
611 if (rv != APR_SUCCESS) {
612 if (rv != AP_FILTER_ERROR) {
613 if (!fmt)
615 "ap_pass_brigade returned %d", rv);
616 else {
617 va_list ap;
618 const char *res;
619 va_start(ap, fmt);
621 va_end(ap);
623 "%s", res);
624 }
626 }
627 return AP_FILTER_ERROR;
628 }
629 return OK;
630}
631
633 apr_bucket_brigade **saveto,
635{
636 apr_bucket *e;
638
639 /* If have never stored any data in the filter, then we had better
640 * create an empty bucket brigade so that we can concat.
641 */
642 if (!(*saveto)) {
643 *saveto = apr_brigade_create(p, f->c->bucket_alloc);
644 }
645
646 for (e = APR_BRIGADE_FIRST(*b);
649 {
650 rv = apr_bucket_setaside(e, p);
651
652 /* If the bucket type does not implement setaside, then
653 * (hopefully) morph it into a bucket type which does, and set
654 * *that* aside... */
655 if (rv == APR_ENOTIMPL) {
656 const char *s;
658
660 if (rv == APR_SUCCESS) {
661 rv = apr_bucket_setaside(e, p);
662 }
663 }
664
665 if (rv != APR_SUCCESS) {
666 srv = rv;
667 /* Return an error but still save the brigade if
668 * ->setaside() is really not implemented. */
669 if (rv != APR_ENOTIMPL) {
670 return rv;
671 }
672 }
673 }
674 APR_BRIGADE_CONCAT(*saveto, *b);
675 return srv;
676}
677
679 void *ctx)
680{
681 ap_filter_t *f = ctx;
682 apr_status_t rv;
683
684 rv = ap_pass_brigade(f, bb);
685
686 /* Before invocation of the flush callback, apr_brigade_write et
687 * al may place transient buckets in the brigade, which will fall
688 * out of scope after returning. Empty the brigade here, to avoid
689 * issues with leaving such buckets in the brigade if some filter
690 * fails and leaves a non-empty brigade. */
692
693 return rv;
694}
695
697{
698 apr_bucket *b;
699
700 b = apr_bucket_flush_create(f->c->bucket_alloc);
702 return ap_pass_brigade(f, bb);
703}
704
706 apr_bucket_brigade *bb, ...)
707{
709 apr_status_t rv;
710
711 va_start(args, bb);
713 va_end(args);
714 return rv;
715}
716
719 const char *fmt,
720 ...)
721{
723 apr_status_t rv;
724
725 va_start(args, fmt);
727 va_end(args);
728 return rv;
729}
731{
732 f->frec->proto_flags = flags ;
733}
#define AP_DECLARE_NONSTD(type)
Definition ap_config.h:77
#define AP_DECLARE(type)
Definition ap_config.h:67
ap hook functions and macros
int n
Definition ap_regex.h:278
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR Standard Headers Support.
return found
Definition core.c:2840
request_rec * r
#define AP_FILTER_ERROR
Definition httpd.h:473
#define AP_NOBODY_WROTE
Definition httpd.h:466
#define OK
Definition httpd.h:456
#define AP_NOBODY_READ
Definition httpd.h:469
ap_filter_rec_t * ap_get_input_filter_handle(const char *name)
apr_status_t ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
ap_filter_rec_t * ap_get_output_filter_handle(const char *name)
void ap_remove_input_filter(ap_filter_t *f)
ap_filter_rec_t * ap_register_output_filter_protocol(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype, unsigned int proto_flags)
apr_status_t(* ap_out_filter_func)(ap_filter_t *f, apr_bucket_brigade *b)
ap_filter_type
apr_status_t ap_pass_brigade(ap_filter_t *next, apr_bucket_brigade *bb)
int(* ap_init_filter_func)(ap_filter_t *f)
ap_filter_t * ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_remove_input_filter_byhandle(ap_filter_t *next, const char *handle)
apr_status_t(* ap_in_filter_func)(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
apr_status_t ap_remove_output_filter_byhandle(ap_filter_t *next, const char *handle)
ap_filter_t * ap_add_input_filter_handle(ap_filter_rec_t *f, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **saveto, apr_bucket_brigade **b, apr_pool_t *p)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
apr_status_t ap_filter_flush(apr_bucket_brigade *bb, void *ctx)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_fputstrs(ap_filter_t *f, apr_bucket_brigade *bb,...)
ap_filter_rec_t * ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter_handle(ap_filter_rec_t *f, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_get_brigade(ap_filter_t *next, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
void ap_filter_protocol(ap_filter_t *f, unsigned int flags)
void ap_remove_output_filter(ap_filter_t *f)
@ AP_FTYPE_CONNECTION
@ AP_FTYPE_PROTOCOL
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_DEBUG
Definition http_log.h:71
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_NOTFOUND
Definition apr_errno.h:463
#define APR_EINVAL
Definition apr_errno.h:711
apr_file_t * f
#define APR_BRIGADE_LAST(b)
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_file_t apr_off_t start
#define APR_BUCKET_NEXT(e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define apr_bucket_setaside(e, p)
#define APR_BRIGADE_FIRST(b)
#define apr_bucket_read(e, str, len, block)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
const char apr_ssize_t int flags
Definition apr_encode.h:168
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
void ap_str_tolower(char *s)
Definition util.c:2410
apr_size_t size
#define apr_toupper(c)
Definition apr_lib.h:233
#define apr_isalpha(c)
Definition apr_lib.h:205
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_vformatter_buff_t const char * fmt
Definition apr_lib.h:175
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
apr_pool_t * b
Definition apr_pools.h:529
apr_pool_t * parent
Definition apr_pools.h:197
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** end
const char * s
Definition apr_strings.h:95
const apr_array_header_t * first
Definition apr_tables.h:207
const char const char *const * args
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static int filter_init(ap_filter_t *f)
Definition mod_filter.c:100
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
This structure is used for recording information about the registered filters. It associates a name w...
ap_filter_type ftype
ap_init_filter_func filter_init_func
ap_filter_func filter_func
const char * name
The representation of a filter chain.
request_rec * r
ap_filter_rec_t * frec
ap_filter_t * next
apr_pool_t * child
Definition apr_pools.c:564
Structure to store things which are per connection.
Definition httpd.h:1152
filter_trie_node * child
Definition util_filter.c:57
filter_trie_child_ptr * children
Definition util_filter.c:66
ap_filter_rec_t * frec
Definition util_filter.c:65
A structure that represents the current request.
Definition httpd.h:845
int eos_sent
Definition httpd.h:1039
struct ap_filter_t * output_filters
Definition httpd.h:1070
request_rec * prev
Definition httpd.h:856
struct ap_filter_t * proto_input_filters
Definition httpd.h:1079
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
struct ap_filter_t * proto_output_filters
Definition httpd.h:1076
struct ap_filter_t * input_filters
Definition httpd.h:1072
ap_out_filter_func out_func
ap_in_filter_func in_func
apr_status_t ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char *fmt,...)
static filter_trie_node * registered_input_filters
#define INSERT_BEFORE(f, before_this)
Definition util_filter.c:41
static void trie_node_link(apr_pool_t *p, filter_trie_node *parent, filter_trie_node *child, int c)
Definition util_filter.c:75
static filter_trie_node * registered_output_filters
static filter_trie_node * trie_node_alloc(apr_pool_t *p, filter_trie_node *parent, char c)
static ap_filter_rec_t * get_filter_handle(const char *name, const filter_trie_node *filter_set)
static void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt, ap_filter_t **p_filt, ap_filter_t **c_filt)
static apr_status_t filter_cleanup(void *ctx)
static ap_filter_t * add_any_filter_handle(ap_filter_rec_t *frec, void *ctx, request_rec *r, conn_rec *c, ap_filter_t **r_filters, ap_filter_t **p_filters, ap_filter_t **c_filters)
apr_status_t ap_pass_brigade_fchk(request_rec *r, apr_bucket_brigade *bb, const char *fmt,...)
#define FILTER_POOL
Definition util_filter.c:32
static ap_filter_rec_t * register_filter(const char *name, ap_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype, filter_trie_node **reg_filter_set)
#define TRIE_INITIAL_SIZE
Definition util_filter.c:71
static ap_filter_t * add_any_filter(const char *name, void *ctx, request_rec *r, conn_rec *c, const filter_trie_node *reg_filter_set, ap_filter_t **r_filters, ap_filter_t **p_filters, ap_filter_t **c_filters)
Apache filter library.
ap_input_mode_t
input filtering modes
Definition util_filter.h:41