typedef struct hf_struct { int state; } hf_struct;
The only field in this structure is a state field. This tells our filter if it
has already sent the configured headers or not. This filter is likely to be
called multiple times for a single request, so we want to be sure that we don’t
send headers on any call other than the first call. The footers are managed
completely differetly, but we will see that later. Most filters will also need
a bucket_brigade in this structure if they want to save any of the data they are
passed for use in later calls. In our case, this filter is a simple pass-through.
Any data we are passed is passed on to the next filter without any modifications.
The next step declares the filter and some variables that we are going to need:
static int hf_filter(ap_filter_t *f, ap_bucket_brigade *bb) { hf_struct *ctx = f->ctx; header_footer_rec *conf; ap_bucket *e; conf = (header_footer_rec *) ap_get_module_config(f->r->per_dir_config, &hf_module); if (ctx == NULL) { f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); }The first variable is an instance of the filter's ctx structure that we just
defined. This is value is always stored in f->ctx, so we start by finding the
ctx pointer from the previous call to this filter. If we have never been called
before this field will be NULL and we will have to allocate memory for this
structure. This is what we are doing in the last three lines of this section.
The conf variable is the module specific configuration for this request. This
is where we have stored the name of the header and footer files as well as the
configured header and footer text. We will use this structure when we determine
what to send. Finally, the variable e is a pointer to a bucket. Remember from
last month that all of the data is stored in buckets. We will use this variable
to create the text buckets to pass to the next filter, and to examine the data that
we are sent.The next step is to send the header information on the first call to this filter:
if (ctx->state == 0) { ctx->state = 1; if (conf->headerf) { request_rec *rr; rr = ap_sub_req_lookup_uri(conf->headerf, f->r); if (rr->status == HTTP_OK) { ap_run_sub_req(rr); } } if (conf->headert) { e = ap_bucket_create_immortal(conf->headert, strlen(conf->headert)); AP_BRIGADE_INSERT_HEAD(bb, e); } }
The first if statement checks to ensure that we haven't already sent the headers.
If we haven't already sent them, then we need to find the information to send and
send it. If it is a file, then we want to use a sub-request. This takes
advantage of Apache's request processing to send the file for us. This file will
also be filtered if any filters are configured for it. The best way to think
of a sub-request in Apache, is that it is the same as requesting the file through
a browser. The ap_run_sub_req function will actually send the file to the client,
so once we have called this function we do not need to do anything else to
finish this portion of the request.