842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
1fd12b55be5aebd93227eb2821285f073e15df2djerenkrantz/* NOTE: Apache's current design doesn't allow a pool to be passed thru,
777a2b42697cb8cb94ac4e73774862f879259c45rbb so we depend on a global to hold the correct pool
777a2b42697cb8cb94ac4e73774862f879259c45rbb** This macro returns true/false if a given filter should be inserted BEFORE
777a2b42697cb8cb94ac4e73774862f879259c45rbb** another filter. This will happen when one of: 1) there isn't another
777a2b42697cb8cb94ac4e73774862f879259c45rbb** filter; 2) that filter has a higher filter type (class); 3) that filter
777a2b42697cb8cb94ac4e73774862f879259c45rbb** corresponds to a different request.
777a2b42697cb8cb94ac4e73774862f879259c45rbb#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
018c3674550f6780e0cebce1f4ffeb9c7674a5c5rbb || (before_this)->r != (f)->r)
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp/* Trie structure to hold the mapping from registered
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp * filter names to filters
7184de27ec1d62a83c41cdeac0953ca9fd661e8csf/* we know core's module_index is 0 */
5b33c03529e21b31bfd2a23fc30b126cb6370376brianptypedef struct {
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp/* Each trie node has an array of pointers to its children.
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp * The array is kept in sorted order so that add_any_filter()
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp * can do a binary search
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp/* Link a trie node to its parent
5b33c03529e21b31bfd2a23fc30b126cb6370376brianpstatic void trie_node_link(apr_pool_t *p, filter_trie_node *parent,
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp new = (filter_trie_child_ptr *)apr_palloc(p, parent->size *
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp parent->children[j].child = parent->children[j - 1].child;
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp/* Allocate a new node for a trie.
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp * If parent is non-NULL, link the new node under the parent node with
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp * key 'c' (or, if an existing child node matches, return that one)
5b33c03529e21b31bfd2a23fc30b126cb6370376brianpstatic filter_trie_node *trie_node_alloc(apr_pool_t *p,
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp (filter_trie_node *)apr_palloc(p, sizeof(filter_trie_node));
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp else { /* No parent node */
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp new_node->children = (filter_trie_child_ptr *)apr_palloc(p,
5b33c03529e21b31bfd2a23fc30b126cb6370376brianpstatic filter_trie_node *registered_output_filters = NULL;
5b33c03529e21b31bfd2a23fc30b126cb6370376brianpstatic filter_trie_node *registered_input_filters = NULL;
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianpstatic ap_filter_rec_t *get_filter_handle(const char *name,
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp const char *n;
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp for (n = name; *n; n++) {
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp if (*n == ch) {
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp else if (*n < ch) {
542f434598f16966bede223e4ee4e201240dace4ianhAP_DECLARE(ap_filter_rec_t *)ap_get_output_filter_handle(const char *name)
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp return get_filter_handle(name, registered_output_filters);
542f434598f16966bede223e4ee4e201240dace4ianhAP_DECLARE(ap_filter_rec_t *)ap_get_input_filter_handle(const char *name)
7a8a0744e378f2343c3ee6787fac0f8f959d2141brianp return get_filter_handle(name, registered_input_filters);
fd492f9543f14fb5bae78e04b135c3448eb9cc56rbbstatic ap_filter_rec_t *register_filter(const char *name,
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp const char *n;
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp *reg_filter_set = trie_node_alloc(FILTER_POOL, NULL, 0);
435c423bdcfa61ff871a9e289d1140f2bac839b8brianp for (n = normalized_name; *n; n++) {
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp filter_trie_node *child = trie_node_alloc(FILTER_POOL, node, *n);
5b33c03529e21b31bfd2a23fc30b126cb6370376brianp trie_node_link(FILTER_POOL, node, child, apr_toupper(*n));
e8f95a682820a599fe41b22977010636be5c2717jim apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup,
fd492f9543f14fb5bae78e04b135c3448eb9cc56rbbAP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
0fdf8c342123fde84405b885fb1720ebc652e10djerenkrantz return register_filter(name, f, filter_init, ftype,
d6f31486d449475eb8656f3f6dc874cac70a12eaniqAP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
d6f31486d449475eb8656f3f6dc874cac70a12eaniq return ap_register_output_filter_protocol(name, filter_func,
ae3dea49b7dbd3cdf991225881cf01e62689af2bniqAP_DECLARE(ap_filter_rec_t *) ap_register_output_filter_protocol(
ae3dea49b7dbd3cdf991225881cf01e62689af2bniq const char *name,
ae3dea49b7dbd3cdf991225881cf01e62689af2bniq unsigned int proto_flags)
e8f95a682820a599fe41b22977010636be5c2717jimstatic ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
bc0ebf8a6b6f96df7f05ced975fc5fd4f5846607jorton apr_pool_t *p = frec->ftype < AP_FTYPE_CONNECTION && r ? r->pool : c->pool;
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(00080)
237b1c198de800d82b737a77ca5e48fe1ff7bc94trawick "a content filter was added without a request: %s", frec->name);
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(00081)
237b1c198de800d82b737a77ca5e48fe1ff7bc94trawick "a protocol filter was added without a request: %s", frec->name);
bc0ebf8a6b6f96df7f05ced975fc5fd4f5846607jorton /* f->r must always be NULL for connection filters */
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb /* If we are adding our first non-connection filter,
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb * Then don't try to find the right location, it is
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb * automatically first.
b0e8ad4dd64745bef003618fdf500b9025e43e56rbb if (frec->ftype < AP_FTYPE_CONNECTION && (*r_filters == *c_filters)) {
e8f95a682820a599fe41b22977010636be5c2717jimstatic ap_filter_t *add_any_filter(const char *name, void *ctx,
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb const char *n;
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb for (n = name; *n; n++) {
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb if (*n == ch) {
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb else if (*n < ch) {
e8f95a682820a599fe41b22977010636be5c2717jim return add_any_filter_handle(node->frec, ctx, r, c, r_filters,
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r ? r->connection : c, APLOGNO(00082)
2a0c3663b66c9af764267ac3c4e140e659598474benAP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
2a0c3663b66c9af764267ac3c4e140e659598474ben return add_any_filter(name, ctx, r, c, registered_input_filters,
435c423bdcfa61ff871a9e289d1140f2bac839b8brianpAP_DECLARE(ap_filter_t *) ap_add_input_filter_handle(ap_filter_rec_t *f,
435c423bdcfa61ff871a9e289d1140f2bac839b8brianp return add_any_filter_handle(f, ctx, r, c, r ? &r->input_filters : NULL,
2a0c3663b66c9af764267ac3c4e140e659598474benAP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx,
2a0c3663b66c9af764267ac3c4e140e659598474ben return add_any_filter(name, ctx, r, c, registered_output_filters,
e57e920838f31508f1418aa4c25ce55b345b2cebrbb r ? &r->proto_output_filters : NULL, &c->output_filters);
435c423bdcfa61ff871a9e289d1140f2bac839b8brianpAP_DECLARE(ap_filter_t *) ap_add_output_filter_handle(ap_filter_rec_t *f,
435c423bdcfa61ff871a9e289d1140f2bac839b8brianp return add_any_filter_handle(f, ctx, r, c, r ? &r->output_filters : NULL,
881aedce0b7a1e63932857ad38c3a5edbcb67617akestatic void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt, ap_filter_t **p_filt,
7a070705443ac7e8df63551c0a1b2544a8ea945bdougm if (*curr == f) {
e8f95a682820a599fe41b22977010636be5c2717jim remove_any_filter(f, f->r ? &f->r->input_filters : NULL,
e8f95a682820a599fe41b22977010636be5c2717jim remove_any_filter(f, f->r ? &f->r->output_filters : NULL,
b1de4d11181d00bd6a3bf45b4b5a7a5f30b2714ejimAP_DECLARE(apr_status_t) ap_remove_input_filter_byhandle(ap_filter_t *next,
b1de4d11181d00bd6a3bf45b4b5a7a5f30b2714ejim const char *handle)
b1de4d11181d00bd6a3bf45b4b5a7a5f30b2714ejimAP_DECLARE(apr_status_t) ap_remove_output_filter_byhandle(ap_filter_t *next,
b1de4d11181d00bd6a3bf45b4b5a7a5f30b2714ejim const char *handle)
e8f95a682820a599fe41b22977010636be5c2717jim * Read data from the next filter in the filter stack. Data should be
91f8fecd254fcdfcde4607b28ee192276c29c1a2rbb * modified in the bucket brigade that is passed in. The core allocates the
91f8fecd254fcdfcde4607b28ee192276c29c1a2rbb * bucket brigade, modules that wish to replace large chunks of data or to
91f8fecd254fcdfcde4607b28ee192276c29c1a2rbb * save data off to the side should probably create their own temporary
91f8fecd254fcdfcde4607b28ee192276c29c1a2rbb * brigade especially for that use.
b1ed4c9098a3c73d140abd3c1f42312e7be3021fgsteinAP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
e8f95a682820a599fe41b22977010636be5c2717jim return next->frec->filter_func.in_func(next, bb, mode, block,
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb/* Pass the buckets to the next filter in the filter stack. If the
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb * current filter is a handler, we should get NULL passed in instead of
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb * the current filter. At that point, we can just call the first filter in
4b86db47932a21da10cd35317b3da737f2b073c4rbb * the stack, or r->output_filters.
e8f95a682820a599fe41b22977010636be5c2717jimAP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next,
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe if ((e = APR_BRIGADE_LAST(bb)) && APR_BUCKET_IS_EOS(e) && next->r) {
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb /* This is only safe because HTTP_HEADER filter is always in
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * the filter stack. This ensures that there is ALWAYS a
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * request-based filter that we can attach this to. If the
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * HTTP_FILTER is removed, and another filter is not put in its
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * place, then handlers like mod_cgi, which attach their own
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * EOS bucket to the brigade will be broken, because we will
edcb7bd7ea2d7175a7f5887be3934231ce0d2060rbb * get two EOS buckets on the same request.
c4955dc69110568b20f1517b8bf113a791bf6496nd /* remember the eos for internal redirects, too */
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim/* Pass the buckets to the next filter in the filter stack
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim * checking return status for filter errors.
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim * returns: OK if ap_pass_brigade returns APR_SUCCESS
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim * AP_FILTER_ERROR if filter error exists
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim * HTTP_INTERNAL_SERVER_ERROR for all other cases
5fcee27172ebd5529ba056deaf01a3755fc4ae05jim * logged with optional errmsg
5fcee27172ebd5529ba056deaf01a3755fc4ae05jimAP_DECLARE(apr_status_t) ap_pass_brigade_fchk(request_rec *r,
eed23c0ffbac879e3502737c44070dc1212daeb0jim const char *fmt,
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(00083)
59bdac473e4f8e7b7aa2548947722c278289ed26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "%s", res);
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb /* If have never stored any data in the filter, then we had better
bfb62a96023822c56c9120e4ee627d4091cc59c2rbb * create an empty bucket brigade so that we can concat.
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley *saveto = apr_brigade_create(p, f->c->bucket_alloc);
42d3dd0fe6973dc43e01f19f964c918e57309295jorton /* If the bucket type does not implement setaside, then
42d3dd0fe6973dc43e01f19f964c918e57309295jorton * (hopefully) morph it into a bucket type which does, and set
42d3dd0fe6973dc43e01f19f964c918e57309295jorton * *that* aside... */
42d3dd0fe6973dc43e01f19f964c918e57309295jorton const char *s;
2bf024084f1b0f2c9617bbd68834f057a3d91686jorton /* Return an error but still save the brigade if
2bf024084f1b0f2c9617bbd68834f057a3d91686jorton * ->setaside() is really not implemented. */
e8f95a682820a599fe41b22977010636be5c2717jimAP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb,
1c708e0bf6df4e4796b166776d14c7a32810a301jorton /* Before invocation of the flush callback, apr_brigade_write et
1c708e0bf6df4e4796b166776d14c7a32810a301jorton * al may place transient buckets in the brigade, which will fall
1c708e0bf6df4e4796b166776d14c7a32810a301jorton * out of scope after returning. Empty the brigade here, to avoid
1c708e0bf6df4e4796b166776d14c7a32810a301jorton * issues with leaving such buckets in the brigade if some filter
1c708e0bf6df4e4796b166776d14c7a32810a301jorton * fails and leaves a non-empty brigade. */
39d25d098171c176443e752773a644c429e88394gsteinAP_DECLARE(apr_status_t) ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
7928dad64ccfb725ff5a76c4dfd15ddc5d5d439fgsteinAP_DECLARE_NONSTD(apr_status_t) ap_fputstrs(ap_filter_t *f,
7928dad64ccfb725ff5a76c4dfd15ddc5d5d439fgstein rv = apr_brigade_vputstrs(bb, ap_filter_flush, f, args);
7928dad64ccfb725ff5a76c4dfd15ddc5d5d439fgsteinAP_DECLARE_NONSTD(apr_status_t) ap_fprintf(ap_filter_t *f,
7928dad64ccfb725ff5a76c4dfd15ddc5d5d439fgstein const char *fmt,
7928dad64ccfb725ff5a76c4dfd15ddc5d5d439fgstein rv = apr_brigade_vprintf(bb, ap_filter_flush, f, fmt, args);
ae3dea49b7dbd3cdf991225881cf01e62689af2bniqAP_DECLARE(void) ap_filter_protocol(ap_filter_t *f, unsigned int flags)