File: content_length_header.t

package info (click to toggle)
libapache2-mod-perl2 2.0.9~1624218-2%2Bdeb8u2
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 11,912 kB
  • ctags: 4,588
  • sloc: perl: 95,064; ansic: 14,527; makefile: 49; sh: 18
file content (158 lines) | stat: -rw-r--r-- 5,992 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*-
use strict;
use warnings FATAL => 'all';

use Apache::Test;
use Apache::TestUtil;
use Apache::TestRequest;

plan tests => 12 * 2 + 3;

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 the most part GET
# and HEAD should behave exactly the same.  however, when Apache
# sees a HEAD request with a C-L header of zero it takes special
# action and removes the C-L header.  this is done to protect against
# handlers that called r->header_only (which was ok in 1.3 but is
# not in 2.0).  So, GET and HEAD behave the same except when the
# content handler (plus filters) end up sending no content.  see
# the lengthy comments in ap_http_header_filter in http_protocol.c.
#
# 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);

    {
        # if the response handler sends no data, and sets no C-L header,
        # the client doesn't get C-L header at all.
        #
        # in 2.0 GET requests get a C-L of zero, while HEAD requests do
        # not due to special processing.
        my $uri = $location;
        my $res = $method->($uri);

        my $cl      = 0;
        my $head_cl = undef;

        ok t_cmp $res->code, 200, "$method $uri code";
        ok t_cmp ($res->header('Content-Length'),
                  $method eq 'GET' ? $cl : $head_cl,
                  "$method $uri C-L header");
        ok t_cmp $res->content, "", "$method $uri content";
    }

    {
        # if the response handler sends no data and sets C-L header,
        # the client should receive the set content length.  in 2.1
        # this is the way it happens.  see protocol.c -r1.150 -r1.151
        #
        # in 2.0 the client doesn't get C-L header for HEAD requests
        # due to special processing, and GET requests get a calculated
        # C-L of zero.
        my $uri = "$location?set_content_length";
        my $res = $method->($uri);

        my $cl      = 0;
        my $head_cl;

        ## 2.2.1, 2.0.56, 2.0.57 were not released
        ## but we use the versions the changes went into
        ## to protect against wierd SVN checkout building.
        ## XXX: I'm starting to think this test is more
        ## trouble then its worth.
        if (have_min_apache_version("2.2.1")) {
          $head_cl = 25;
        }
        elsif (have_min_apache_version("2.2.0")) {
          # $head_cl = undef; # avoid warnings
        }
        elsif (have_min_apache_version("2.0.56")) {
          $head_cl = 25;
        }
        else {
          # $head_cl = undef; # avoid warnings
        }

        ok t_cmp $res->code, 200, "$method $uri code";
        ok t_cmp ($res->header('Content-Length'),
                  $method eq 'GET' ? $cl : $head_cl,
                  "$method $uri C-L header");
        ok t_cmp $res->content, "", "$method $uri content";
    }

    {
        # if the response handler sends data, and sets no C-L header,
        # the client doesn't get C-L header.
        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";

        my $content = $method eq 'GET' ? 'This is a response string' : '';
        ok t_cmp $res->content, $content, "$method $uri content";
    }

    {
        # 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?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";

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