Filtering I/O in Apache 2.0: Part 2 Page 3
The final step in this filter is to deal with the footers:
e = AP_BRIGADE_LAST(bb); if (AP_BUCKET_IS_EOS(e)) { ap_bucket_brigade *end; end = ap_brigade_split(bb, e); if (!AP_BRIGADE_EMPTY(bb)) { ap_pass_brigade(f->next, bb); } ap_brigade_destroy(bb); bb = end; if (conf->headerf) { request_rec *rr; rr = ap_sub_req_lookup_uri(conf->footerf, f->r); if (rr->status == HTTP_OK) { ap_run_sub_req(rr); } } if (conf->footert) { ap_bucket *foot; foot = ap_bucket_create_immortal(conf->footert, strlen(conf->footert)); AP_BUCKET_INSERT_BEFORE(e, foot); } } ap_pass_brigade(f->next, bb); return APR_SUCCESS; }As I mentioned above, determining when to send the footers is done differently than the headers. In this case, we only want to send the footers when we know that we are at the end of the response. Filters know when they are seeing the end of a response, because they are given an EOS bucket. An EOS bucket is a special bucket created by Apache to signify the "end of stream". Another feature of EOS buckets is that they are always at the end of a brigade, so to determine if we are at the end, we get the last bucket in the brigade and check if it is an EOS bucket. If it isn't, then we just pass the data we have just been given to the next filter with the ap_pass_brigade function.
If this brigade does have the end of the request, then we need to send out the footers for this page. To make processing easier, we treat both files and strings the same. In this case, that means sending the data we have before we try to send the footer data. If we didn't do this, and we tried to send a file using a sub-request then the file would be delivered before the data we have just been passed. To send the data we have, we must split the brigade just before the EOS bucket. This is done with ap_brigade_split. If the new brigade is not empty then we need to send it to the next filter. Oce we have either sent the brigade to the next filer, or done nothing with it, we must destroy the brigade, or we will leak memory.
At this point sending the footer file is the same as sending the header file, so we won't go into any detail about that. Sending the footer string starts by creating the bucket, same as the header string. This time, instead of inserting the bucket at the start of the array, we want to insert it just before the EOS bucket. We know that e is pointing to the EOS bucket, because we set that up earlier in the function, so we use AP_BUCKET_INSERT_BEFORE to make sure that the footer bucket is inserted in the correct place.