Geoffrey Young wrote:

As mentioned earlier I think the bug is
in the headers_out filter, which received EOS (since on HEAD apache
scratches the response body) and no body. So it takes the liberty to
nuke the C-L header, which I'm not sure is a good thing. When we send
some body, headers_out sends the headers before seeing EOS and therefore
it can't tell whether the body is coming or not, so it leaves the C-L
header alone. Which is at least inconsistent.


ok, I think I see what is going on, but it's different than what you see :)

first, apache calls the C-L filter, which has no regard for any existing C-L
header and calculates its own if it can.  so, in your test case the call to
$r->set_content_length(25) is overwritten by the real C-L of zero, as
calculated by the C-L filter.

next the header filter kicks in.  inside the header filter is this bit of logic:

      if (r->header_only
        && (clheader = apr_table_get(r->headers_out, "Content-Length"))
        && !strcmp(clheader, "0")) {
        apr_table_unset(r->headers_out, "Content-Length");
    }

which treats HEAD requests with a C-L of zero as a special case.  and, in
fact, that is what you have sent it, at least in the test case.  this is why
GET and HEAD differ in this instance, because you haven't sent any real
content and a C-L of 0 is special.

so, I don't see the bug.  well, I do see it, except that it is intentionally
coded to be as such, which turns the bug into a feature.

Thanks Geoff for looking at the source code and giving us the full story. I've now converted it into the comments in the t/apache/content_length_header.t test and I also used Glenn's suggestion to use $r->rflush, which gives us:


# 2. even though the spec says that content handlers should send an
# identical response for GET and HEAD requests, some folks try to
# avoid the overhead of generating the response body, which Apache is
# going to discard anyway for HEAD requests. The following discussion
# assumes that we deal with a HEAD request.
#
# When Apache sees EOS and no headers and no response body were sent,
# ap_content_length_filter (httpd-2.0/server/protocol.c) sets C-L to
# 0. Later on ap_http_header_filter
# (httpd-2.0/modules/http/http_protocol.c) removes the C-L header for
# the HEAD requests
#
# the workaround is to force the sending of the response headers,
# before EOS was sent. The simplest solution is to use rflush():
#
# if ($r->header_only) { # HEAD
#     $body_len = calculate_body_len();
#     $r->set_content_length($body_len);
#     $r->rflush;
# }
# else {                 # GET
#     # generate and send the body
# }
#
# now if the handler sets the C-L header it'll be delivered to the
# client unmodified.


-- __________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com

--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Reply via email to