I'm currently writing a module for 2.0 which needs to observe the traffic to and from various handlers. The approach I'm using is to register input and output filters of type AP_FTYPE_PROTOCOL+1 (so I get headers, but don't see encrypted traffic), and add them in a create_request hook. However, when I do this, I see some odd behavour, which I think is a bug.
Long story short, it looks like the HTTP input and output handlers don't get added properly. First, when I send a GET with a body, Apache blocks hangs in an attempt to read HUGE_STRING_LEN from core_in, which is caused by the HTTP input filter's absence, since normally it would trim that down based on the content-length or chunk size. Second, Apache's responses are missing their HTTP headers. (Under 2.0, I get both problems; with the latest 2.1 I only see the latter). I can provide code for a module that will create the problems.
I found a logic problem in util_filter.c, add_any_filter_handle(), which explains this. Basically, if more than one protocol filter is added to a request, the request->{input,output}_filters ptr isn't updated properly. Below is a patch. I've tested it with a 2.1 build that I got from CVS earlier today, and it solves my problem without noticably causing any others. Perhaps someone with a test environment can run this through some hoops.
Thanks, Jim
--- server/util_filter.c.orig 2003-03-10 15:19:47.809999000 -0800 +++ server/util_filter.c 2003-03-10 16:25:52.199998000 -0800 @@ -340,24 +340,30 @@ if (INSERT_BEFORE(f, *outf)) { f->next = *outf;
- if (*outf) {
- ap_filter_t *first = NULL;
+ if (r) {
+ /* push the p_filter back */
+ if (outf == c_filters && *p_filters == *outf)
+ *p_filters = f;
+
+ /* push the r_filter back */
+ if ( (outf == c_filters || outf == p_filters) &&
+ *r_filters == *outf) {
+ *r_filters = f;
+ }
+ /* now set the previous filter's next ptr (unless we just
+ * changed r_filter) */
+ else if (outf != r_filters) {
+ ap_filter_t *first = NULL;
+
+ first = *r_filters;
+ while (first && (first->next != (*outf))) {
+ first = first->next;
+ }- if (r) {
- /* If we are adding our first non-connection filter,
- * Then don't try to find the right location, it is
- * automatically first.
- */
- if (*r_filters != *c_filters) {
- first = *r_filters;
- while (first && (first->next != (*outf))) {
- first = first->next;
- }
+ if (first && first != (*outf)) {
+ first->next = f;
}
}
- if (first && first != (*outf)) {
- first->next = f;
- }
}
*outf = f;
}