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