httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stas Bekman <s...@stason.org>
Subject rfc: new API to traverse filter chains
Date Tue, 01 Apr 2003 07:45:23 GMT
in mod_perl 2.0 we register only four filter names (in:out:req:conn) and then 
we install the actuall perl callbacks using one of these four filter names and 
storing the actual filter's callback information in f->ctx. If later on we 
want to do something with an inserted filter we have no API to find it, since 
it's not identified by name, but the data inside f->ctx. Therefore we need a 
new API to traverse the filter chain and find what we want using a custom 
callback.

Here is the API and implementation that I came up with (it needs the docco and 
the standard DECLARE stuff, which I ask to disregard for now and concentrate 
on the API/implementation itself; once it's polished I'll post a complete patch).

The function that I'm requesting to add is somewhat similar to apr_table_do.

typedef int (ap_filter_chain_traverse_fh_t)(void *data, ap_filter_t *f);
int ap_filter_chain_traverse(ap_filter_chain_traverse_fh_t *traverse,
                              void *data, ap_filter_t **chain);

int ap_filter_chain_traverse(ap_filter_chain_traverse_fh_t *traverse,
                                     void *data, ap_filter_t **chain)
{
     int rv = 0;
     ap_filter_t *curr = *chain;

     while (curr) {
         if ((rv = (*traverse)(data, curr)) != 0) {
             return rv;
         }
         curr = curr->next;
     }
     return rv;
}

I'm not sure regarding the chain argument. Looking at the util_filter.c, it 
looks in proto_ and normal chain. Could there be a problem on the caller side?
Won't it be enough to use one of r->output_filters, c->output_filters, 
r->input_filters, c->input_filters if all I care is the custom filters?

Here is an example of usage by mod_perl 2.0. This is an implementation of a 
function that will remove a filter by its perl handler name, e.g.:

   $r->remove_output_filter("TestHandler::out_filter");

there is a wrapper that translates this perl-side call to C's 
modperl_filter_remove_by_handler_name().

typedef struct {
     char* filter_name;
     char* handler_name;
     ap_filter_t* f;
} filter_chain_traverse_t;

static int find_filter_by_handler_name(void *data, ap_filter_t *f)
{
     apr_pool_t* p = f->r ? f->r->pool : f->c->pool;
     filter_chain_traverse_t* traverse = (filter_chain_traverse_t*)data;
     char *normalized_name;

     /* 'name' in frec is always lowercased */
     normalized_name = apr_pstrdup(p, traverse->filter_name);
     ap_str_tolower(normalized_name);

     /* skip non-mod_perl filters */
     if (strNE(f->frec->name, normalized_name)) {
         return 0;
     } else {
         modperl_filter_ctx_t *ctx = f->ctx;
         if (strEQ(ctx->handler->name, traverse->handler_name)) {
             traverse->f = f;
             return 1; /* found what we wanted */
         }
     }

     return 0;
}

/*  modperl_filter_remove_by_handler_name(aTHX_ r, c,
  *                                        MP_OUTPUT_FILTER_MODE,
  *                                        "MyFilter::output_lc")
  */
void modperl_filter_remove_by_handler_name(pTHX_ request_rec *r,
                                            conn_rec *c,
                                            modperl_filter_mode_e mode,
                                            char* handler_name)
{
     int rv = 0;
     apr_pool_t *pool = r ? r->pool : c->pool;
     ap_filter_t *f;
     filter_chain_traverse_t *traverse =
         apr_pcalloc(pool, sizeof(filter_chain_traverse_t*));

     /* XXX: generalize for conn/req in/out */
     traverse->filter_name = MP_FILTER_REQUEST_OUTPUT_NAME;
     traverse->handler_name = handler_name;

     rv = ap_filter_chain_traverse(find_filter_by_handler_name, traverse,
                                   &r->output_filters); /* XXX: generalize */
     if (rv) {
         f = traverse->f; /* XXX: validate */
         MP_TRACE_f(MP_FUNC, "found filter handler %s\n", handler_name);
     }
     else {
         Perl_croak(aTHX_ "unable to find filter handler '%s'\n", handler_name);
     }

     MP_TRACE_f(MP_FUNC, "removing filter %s\n", handler_name);
     if (mode == MP_INPUT_FILTER_MODE) {
         ap_remove_input_filter(f);
     }
     else {
         ap_remove_output_filter(f);
     }
}


__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Mime
View raw message