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

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);
        }
        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.

Latest Posts

Related Stories