Filtering I/O in Apache 2.0: Part 2 Page 3

If we are using a configured string as the header, then we need to create a bucket to store the string before we can pass it down to the next filter. In this case, we are going to use an immortal bucket because the memory for the string was allocated earlier, and we don't want to copy it again if we can help it. Once we have created the bucket, we have to actually put it in the brigade. If we don't put it in the brigade then none of the later filters will get to see the data. Since the final filter is the thing that actually sends the data to the client, we need to be sure that the data is sent to the next filter. Actually sending the data is done later in the function, as we will see below. It is also important that this bucket goes at the beginning of this brigade. Putting this bucket at the start of the brigade is accomplished with AP_BRIGADE_INSERT_HEAD.

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);
        bb = end;
        if (conf->headerf) {
            request_rec *rr;
            rr = ap_sub_req_lookup_uri(conf->footerf, f->r);
            if (rr->status == HTTP_OK) {
        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.

This article was originally published on Oct 23, 2000
Page 3 of 4

Thanks for your registration, follow us on our social networks to keep up-to-date