]> granicus.if.org Git - apache/blob - server/util_filter.c
add "-l" option to indicate interval is based on localtime not gmt
[apache] / server / util_filter.c
1 /* Copyright 2000-2004 The Apache Software Foundation
2  *
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
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #define APR_WANT_STRFUNC
17 #include "apr_want.h"
18 #include "apr_lib.h"
19 #include "apr_hash.h"
20 #include "apr_strings.h"
21
22 #include "httpd.h"
23 #include "http_log.h"
24 #include "util_filter.h"
25
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
28 */
29 #define FILTER_POOL     apr_hook_global_pool
30 #include "apr_hooks.h"   /* for apr_hook_global_pool */
31
32 /*
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.
37 */
38 #define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
39                            || (before_this)->frec->ftype > (f)->frec->ftype \
40                            || (before_this)->r != (f)->r)
41
42 /* Trie structure to hold the mapping from registered
43  * filter names to filters
44  */
45
46 typedef struct filter_trie_node filter_trie_node;
47
48 typedef struct {
49     int c;
50     filter_trie_node *child;
51 } filter_trie_child_ptr;
52
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
56  */
57 struct filter_trie_node {
58     ap_filter_rec_t *frec;
59     filter_trie_child_ptr *children;
60     int nchildren;
61     int size;
62 };
63
64 #define TRIE_INITIAL_SIZE 4
65
66 /* Link a trie node to its parent
67  */
68 static void trie_node_link(apr_pool_t *p, filter_trie_node *parent,
69                            filter_trie_node *child, int c)
70 {
71     int i, j;
72
73     if (parent->nchildren == parent->size) {
74         filter_trie_child_ptr *new;
75         parent->size *= 2;
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;
81     }
82
83     for (i = 0; i < parent->nchildren; i++) {
84         if (c == parent->children[i].c) {
85             return;
86         }
87         else if (c < parent->children[i].c) {
88             break;
89         }
90     }
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;
94     }
95     parent->children[i].c = c;
96     parent->children[i].child = child;
97
98     parent->nchildren++;
99 }
100
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)
104  */
105 static filter_trie_node *trie_node_alloc(apr_pool_t *p,
106                                          filter_trie_node *parent, char c)
107 {
108     filter_trie_node *new_node;
109     if (parent) {
110         int i;
111         for (i = 0; i < parent->nchildren; i++) {
112             if (c == parent->children[i].c) {
113                 return parent->children[i].child;
114             }
115             else if (c < parent->children[i].c) {
116                 break;
117             }
118         }
119         new_node =
120             (filter_trie_node *)apr_palloc(p, sizeof(filter_trie_node));
121         trie_node_link(p, parent, new_node, c);
122     }
123     else { /* No parent node */
124         new_node = (filter_trie_node *)apr_palloc(p,
125                                                   sizeof(filter_trie_node));
126     }
127
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));
133     return new_node;
134 }
135
136 static filter_trie_node *registered_output_filters = NULL;
137 static filter_trie_node *registered_input_filters = NULL;
138
139
140 static apr_status_t filter_cleanup(void *ctx)
141 {
142     registered_output_filters = NULL;
143     registered_input_filters = NULL;
144     return APR_SUCCESS;
145 }
146
147 static ap_filter_rec_t *get_filter_handle(const char *name,
148                                           const filter_trie_node *filter_set)
149 {
150     if (filter_set) {
151         const char *n;
152         const filter_trie_node *node;
153
154         node = filter_set;
155         for (n = name; *n; n++) {
156             int start, end;
157             start = 0;
158             end = node->nchildren - 1;
159             while (end >= start) {
160                 int middle = (end + start) / 2;
161                 char ch = node->children[middle].c;
162                 if (*n == ch) {
163                     node = node->children[middle].child;
164                     break;
165                 }
166                 else if (*n < ch) {
167                     end = middle - 1;
168                 }
169                 else {
170                     start = middle + 1;
171                 }
172             }
173             if (end < start) {
174                 node = NULL;
175                 break;
176             }
177         }
178
179         if (node && node->frec) {
180             return node->frec;
181         }
182     }
183     return NULL;
184 }
185
186 AP_DECLARE(ap_filter_rec_t *)ap_get_output_filter_handle(const char *name)
187 {
188     return get_filter_handle(name, registered_output_filters);
189 }
190
191 AP_DECLARE(ap_filter_rec_t *)ap_get_input_filter_handle(const char *name)
192 {
193     return get_filter_handle(name, registered_input_filters);
194 }
195
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)
201 {
202     ap_filter_rec_t *frec;
203     char *normalized_name;
204     const char *n;
205     filter_trie_node *node;
206
207     if (!*reg_filter_set) {
208         *reg_filter_set = trie_node_alloc(FILTER_POOL, NULL, 0);
209     }
210
211     normalized_name = apr_pstrdup(FILTER_POOL, name);
212     ap_str_tolower(normalized_name);
213
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));
219         }
220         node = child;
221     }
222     if (node->frec) {
223         frec = node->frec;
224     }
225     else {
226         frec = apr_palloc(FILTER_POOL, sizeof(*frec));
227         node->frec = frec;
228         frec->name = normalized_name;
229     }
230     frec->filter_func = filter_func;
231     frec->filter_init_func = filter_init;
232     frec->ftype = ftype;
233     
234     apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup, 
235                               apr_pool_cleanup_null);
236     return frec;
237 }
238
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)
243 {
244     ap_filter_func f;
245     f.in_func = filter_func;
246     return register_filter(name, f, filter_init, ftype,
247                            &registered_input_filters);
248 }                                                                    
249
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)
254 {
255     ap_filter_func f;
256     f.out_func = filter_func;
257     return register_filter(name, f, filter_init, ftype,
258                            &registered_output_filters);
259 }
260
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)
266 {
267     apr_pool_t* p = r ? r->pool : c->pool;
268     ap_filter_t *f = apr_palloc(p, sizeof(*f));
269     ap_filter_t **outf;
270
271     if (frec->ftype < AP_FTYPE_PROTOCOL) {
272         if (r) {
273             outf = r_filters;
274         }
275         else {
276             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
277                       "a content filter was added without a request: %s", frec->name);
278             return NULL;
279         }
280     }
281     else if (frec->ftype < AP_FTYPE_CONNECTION) {
282         if (r) {
283             outf = p_filters;
284         }
285         else {
286             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
287                          "a protocol filter was added without a request: %s", frec->name);
288             return NULL;
289         }
290     }
291     else {
292         outf = c_filters;
293     }
294
295     f->frec = frec;
296     f->ctx = ctx;
297     f->r = r;
298     f->c = c;
299     f->next = NULL;
300
301     if (INSERT_BEFORE(f, *outf)) {
302         f->next = *outf;
303
304         if (*outf) {
305             ap_filter_t *first = NULL;
306
307             if (r) {
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.
311                  */
312                 if (*r_filters != *c_filters) {
313                     first = *r_filters;
314                     while (first && (first->next != (*outf))) {
315                         first = first->next;
316                     }
317                 }
318             }
319             if (first && first != (*outf)) {
320                 first->next = f;
321             }
322         }
323         *outf = f;
324     }
325     else {
326         ap_filter_t *fscan = *outf;
327         while (!INSERT_BEFORE(f, fscan->next))
328             fscan = fscan->next;
329
330         f->next = fscan->next;
331         fscan->next = f;
332     }
333
334     if (frec->ftype < AP_FTYPE_CONNECTION && (*r_filters == *c_filters)) {
335         *r_filters = *p_filters;
336     }
337     return f;
338 }
339
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)
346 {
347     if (reg_filter_set) {
348         const char *n;
349         const filter_trie_node *node;
350
351         node = reg_filter_set;
352         for (n = name; *n; n++) {
353             int start, end;
354             start = 0;
355             end = node->nchildren - 1;
356             while (end >= start) {
357                 int middle = (end + start) / 2;
358                 char ch = node->children[middle].c;
359                 if (*n == ch) {
360                     node = node->children[middle].child;
361                     break;
362                 }
363                 else if (*n < ch) {
364                     end = middle - 1;
365                 }
366                 else {
367                     start = middle + 1;
368                 }
369             }
370             if (end < start) {
371                 node = NULL;
372                 break;
373             }
374         }
375
376         if (node && node->frec) {
377             return add_any_filter_handle(node->frec, ctx, r, c, r_filters, 
378                                          p_filters, c_filters);
379         }
380     }
381
382     ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
383                  "an unknown filter was not added: %s", name);
384     return NULL;
385 }
386
387 AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
388                                               request_rec *r, conn_rec *c)
389 {
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);
393 }
394
395 AP_DECLARE(ap_filter_t *) ap_add_input_filter_handle(ap_filter_rec_t *f,
396                                                      void *ctx,
397                                                      request_rec *r,
398                                                      conn_rec *c)
399 {
400     return add_any_filter_handle(f, ctx, r, c, r ? &r->input_filters : NULL,
401                                  r ? &r->proto_input_filters : NULL, 
402                                  &c->input_filters);
403 }
404
405 AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx,
406                                                request_rec *r, conn_rec *c)
407 {
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);
411 }
412
413 AP_DECLARE(ap_filter_t *) ap_add_output_filter_handle(ap_filter_rec_t *f,
414                                                       void *ctx,
415                                                       request_rec *r,
416                                                       conn_rec *c)
417 {
418     return add_any_filter_handle(f, ctx, r, c, r ? &r->output_filters : NULL,
419                                  r ? &r->proto_output_filters : NULL,
420                                  &c->output_filters);
421 }
422
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)
425 {
426     ap_filter_t **curr = r_filt ? r_filt : c_filt;
427     ap_filter_t *fscan = *curr;
428
429     if (p_filt && *p_filt == f)
430         *p_filt = (*p_filt)->next;
431
432     if (*curr == f) {
433         *curr = (*curr)->next;
434         return;
435     }
436
437     while (fscan->next != f) {
438         if (!(fscan = fscan->next)) {
439             return;
440         }
441     }
442
443     fscan->next = f->next;
444 }
445
446 AP_DECLARE(void) ap_remove_input_filter(ap_filter_t *f)
447 {
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);
451 }
452
453 AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f)
454 {
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);
458 }
459
460 /* 
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.
466  */
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,
471                                         apr_off_t readbytes)
472 {
473     if (next) {
474         return next->frec->filter_func.in_func(next, bb, mode, block, 
475                                                readbytes);
476     }
477     return AP_NOBODY_READ;
478 }
479
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.
484  */
485 AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next, 
486                                          apr_bucket_brigade *bb)
487 {
488     if (next) {
489         apr_bucket *e;
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.
498              */
499             next->r->eos_sent = 1;
500
501             /* remember the eos for internal redirects, too */
502             if (next->r->prev) {
503                 request_rec *prev = next->r->prev;
504
505                 while (prev) {
506                     prev->eos_sent = 1;
507                     prev = prev->prev;
508                 }
509             }
510         }
511         return next->frec->filter_func.out_func(next, bb);
512     }
513     return AP_NOBODY_WROTE;
514 }
515
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)
519 {
520     apr_bucket *e;
521     apr_status_t rv;
522
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.
525      */
526     if (!(*saveto)) {
527         *saveto = apr_brigade_create(p, f->c->bucket_alloc);
528     }
529     
530     for (e = APR_BRIGADE_FIRST(*b);
531          e != APR_BRIGADE_SENTINEL(*b);
532          e = APR_BUCKET_NEXT(e))
533     {
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) {
539             return rv;
540         }
541     }
542     APR_BRIGADE_CONCAT(*saveto, *b);
543     return APR_SUCCESS;
544 }
545
546 AP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb, 
547                                                 void *ctx)
548 {
549     ap_filter_t *f = ctx;
550
551     return ap_pass_brigade(f, bb);
552 }
553
554 AP_DECLARE(apr_status_t) ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
555 {
556     apr_bucket *b;
557
558     b = apr_bucket_flush_create(f->c->bucket_alloc);
559     APR_BRIGADE_INSERT_TAIL(bb, b);
560     return ap_pass_brigade(f, bb);
561 }
562
563 AP_DECLARE_NONSTD(apr_status_t) ap_fputstrs(ap_filter_t *f,
564                                             apr_bucket_brigade *bb, ...)
565 {
566     va_list args;
567     apr_status_t rv;
568
569     va_start(args, bb);
570     rv = apr_brigade_vputstrs(bb, ap_filter_flush, f, args);
571     va_end(args);
572     return rv;
573 }
574
575 AP_DECLARE_NONSTD(apr_status_t) ap_fprintf(ap_filter_t *f,
576                                            apr_bucket_brigade *bb,
577                                            const char *fmt,
578                                            ...)
579 {
580     va_list args;
581     apr_status_t rv;
582
583     va_start(args, fmt);
584     rv = apr_brigade_vprintf(bb, ap_filter_flush, f, fmt, args);
585     va_end(args);
586     return rv;
587 }