stas 2004/08/04 11:30:54
Modified: t/apache content_length_header.t
t/response/TestApache content_length_header.pm
Log:
1) improve the discussion based on input from Geoff
2) restore the explicit HEAD test where we want to get C-L, but no body is
sent (this time using $r->rflush to force an early headers sending)
Revision Changes Path
1.2 +58 -20 modperl-2.0/t/apache/content_length_header.t
Index: content_length_header.t
===================================================================
RCS file: /home/cvs/modperl-2.0/t/apache/content_length_header.t,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -u -r1.1 -r1.2
--- content_length_header.t 2 Aug 2004 18:51:25 -0000 1.1
+++ content_length_header.t 4 Aug 2004 18:30:54 -0000 1.2
@@ -1,29 +1,26 @@
use strict;
use warnings FATAL => 'all';
-# testing nuances of the HEAD request (e.g. when C-L header makes it
-# through)
-#
-# because apache proclaims itself governor of the C-L header via
-# the C-L filter, the important thing to test here is not when
-# a C-L header is allowed to pass, but rather whether GET and HEAD
-# behave the same wrt C-L under varying circumstances.
-# for more discussion on why it is important to get HEAD requests
-# right, see these threads from the mod_perl list
-# http://marc.theaimsgroup.com/?l=apache-modperl&m=108647669726915&w=2
-# http://marc.theaimsgroup.com/?t=109122984600001&r=1&w=2
-# as well as this bug report from mozilla, which shows how they
-# are using HEAD requests in the wild
-# http://bugzilla.mozilla.org/show_bug.cgi?id=245447
-
use Apache::Test;
use Apache::TestUtil;
use Apache::TestRequest;
-plan tests => 12 * 2, todo => [2,5];
+plan tests => 12 * 2 + 3, todo => [2,5];
my $location = "/TestApache__content_length_header";
+# 1. because Apache proclaims itself governor of the C-L header via
+# the C-L filter (ap_content_length_filter at
+# httpd-2.0/server/protocol.c), test whether GET and HEAD behave the
+# same wrt C-L under varying circumstances. for more discussion on
+# why it is important to get HEAD requests right, see these threads
+# from the mod_perl list
+# http://marc.theaimsgroup.com/?l=apache-modperl&m=108647669726915&w=2
+# http://marc.theaimsgroup.com/?t=109122984600001&r=1&w=2
+# as well as this bug report from mozilla, which shows how they
+# are using HEAD requests in the wild
+# http://bugzilla.mozilla.org/show_bug.cgi?id=245447
+
foreach my $method qw(GET HEAD) {
no strict qw(refs);
@@ -34,7 +31,8 @@
my $uri = $location;
my $res = $method->($uri);
ok t_cmp $res->code, 200, "$method $uri code";
- ok t_cmp $res->header('Content-Length'), undef, "$method $uri C-L header";
+ ok t_cmp $res->header('Content-Length'), undef,
+ "$method $uri C-L header";
ok t_cmp $res->content, "", "$method $uri content";
}
@@ -44,7 +42,8 @@
my $uri = "$location?set_content_length";
my $res = $method->($uri);
ok t_cmp $res->code, 200, "$method $uri code";
- ok t_cmp $res->header('Content-Length'), undef, "$method $uri C-L header";
+ ok t_cmp $res->header('Content-Length'), undef,
+ "$method $uri C-L header";
ok t_cmp $res->content, "", "$method $uri content";
}
@@ -54,7 +53,8 @@
my $uri = "$location?send_body";
my $res = $method->($uri);
ok t_cmp $res->code, 200, "$method $uri code";
- ok t_cmp $res->header('Content-Length'), undef, "$method $uri C-L header";
+ ok t_cmp $res->header('Content-Length'), undef,
+ "$method $uri C-L header";
my $content = $method eq 'GET' ? 'This is a response string' : '';
ok t_cmp $res->content, $content, "$method $uri content";
@@ -66,9 +66,47 @@
my $uri = "$location?send_body+set_content_length";
my $res = $method->($uri);
ok t_cmp $res->code, 200, "$method $uri code";
- ok t_cmp $res->header('Content-Length'), 25, "$method $uri C-L header";
+ ok t_cmp $res->header('Content-Length'), 25,
+ "$method $uri C-L header";
my $content = $method eq 'GET' ? 'This is a response string' : '';
ok t_cmp $res->content, $content, "$method $uri content";
}
+}
+
+# 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.
+
+{
+ # if the response handler sends data (e.g. one char string), and
+ # sets C-L header, the client gets the C-L header
+ my $uri = "$location?head_no_body+set_content_length";
+ my $res = HEAD $uri;
+ ok t_cmp $res->code, 200, "HEAD $uri code";
+ ok t_cmp $res->header('Content-Length'), 25, "HEAD $uri C-L header";
+ ok t_cmp $res->content, '', "HEAD $uri content";
}
1.2 +8 -3 modperl-2.0/t/response/TestApache/content_length_header.pm
Index: content_length_header.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/t/response/TestApache/content_length_header.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -u -r1.1 -r1.2
--- content_length_header.pm 2 Aug 2004 18:51:25 -0000 1.1
+++ content_length_header.pm 4 Aug 2004 18:30:54 -0000 1.2
@@ -1,6 +1,6 @@
package TestApache::content_length_header;
-# see the client for the comments
+# see the client t/apache/content_length_header.t for the comments
use strict;
use warnings FATAL => 'all';
@@ -25,9 +25,14 @@
}
if ($args =~ /send_body/) {
- # really could send just about anything, since Apache discards
- # the response body on HEAD requests
$r->print($body);
+ }
+
+ if ($args =~ /head_no_body/) {
+ if ($r->header_only) {
+ # see #2 in the discussion in the client
+ $r->rflush;
+ }
}
Apache::OK;