| # |
| # Test the LimitRequestLine, LimitRequestFieldSize, LimitRequestFields, |
| # and LimitRequestBody directives. |
| # |
| use strict; |
| use warnings FATAL => 'all'; |
| |
| use Apache::Test; |
| use Apache::TestRequest; |
| use Apache::TestUtil; |
| |
| # |
| # These values are chosen to exceed the limits in extra.conf, namely: |
| # |
| # LimitRequestLine @limitrequestline@ |
| # LimitRequestFieldSize 1024 |
| # LimitRequestFields 32 |
| # <Directory @SERVERROOT@/htdocs/apache/limits> |
| # LimitRequestBody 65536 |
| # </Directory> |
| # |
| |
| my $limitrequestlinex2 = Apache::Test::config()->{vars}->{limitrequestlinex2}; |
| |
| my @conditions = qw(requestline fieldsize fieldcount bodysize merged_fieldsize); |
| |
| my %params = ('requestline-succeed' => "/apache/limits/", |
| 'requestline-fail' => ("/apache/limits/" . ('a' x $limitrequestlinex2)), |
| 'fieldsize-succeed' => 'short value', |
| 'fieldsize-fail' => ('a' x 2048), |
| 'fieldcount-succeed' => 1, |
| 'fieldcount-fail' => 64, |
| 'bodysize-succeed' => ('a' x 1024), |
| 'bodysize-fail' => ('a' x 131072), |
| 'merged_fieldsize-succeed' => ('a' x 500), |
| 'merged_fieldsize-fail' => ('a' x 600), |
| ); |
| my %xrcs = ('requestline-succeed' => 200, |
| 'requestline-fail' => 414, |
| 'fieldsize-succeed' => 200, |
| 'fieldsize-fail' => 400, |
| 'fieldcount-succeed' => 200, |
| 'fieldcount-fail' => 400, |
| 'bodysize-succeed' => 200, |
| 'bodysize-fail' => 413, |
| 'merged_fieldsize-succeed' => 200, |
| 'merged_fieldsize-fail' => 400, |
| ); |
| |
| my $res; |
| |
| if (!have_min_apache_version("2.2.32")) { |
| $xrcs{"merged_fieldsize-fail"} = 200; |
| } |
| |
| # |
| # Two tests for each of the conditions, plus two more for the |
| # chunked version of the body-too-large test IFF we have the |
| # appropriate level of LWP support. |
| # |
| |
| my $no_chunking = defined($LWP::VERSION) && $LWP::VERSION < 5.60; |
| if ($no_chunking) { |
| print "# Chunked upload tests will NOT be performed;\n", |
| "# LWP 5.60 or later is required and you only have ", |
| "$LWP::VERSION installed.\n"; |
| } |
| |
| my $subtests = (@conditions * 2) + 2; |
| plan tests => $subtests, \&need_lwp; |
| |
| use vars qw($expected_rc); |
| |
| my $testnum = 1; |
| foreach my $cond (@conditions) { |
| foreach my $goodbad (qw(succeed fail)) { |
| my $param = $params{"$cond-$goodbad"}; |
| $expected_rc = $xrcs{"$cond-$goodbad"}; |
| my $resp; |
| if ($cond eq 'fieldcount') { |
| my %fields; |
| for (my $i = 1; $i <= $param; $i++) { |
| $fields{"X-Field-$i"} = "Testing field $i"; |
| } |
| print "# Testing LimitRequestFields; should $goodbad\n"; |
| $resp = GET('/apache/limits/', %fields, 'X-Subtest' => $testnum); |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| $testnum++; |
| } |
| elsif ($cond eq 'bodysize') { |
| # |
| # Make sure the last situation is keepalives off.. |
| # |
| foreach my $chunked (qw(1 0)) { |
| print "# Testing LimitRequestBody; should $goodbad\n"; |
| set_chunking($chunked); |
| # |
| # Note that this tests different things depending upon |
| # the chunking state. The content-body will not even |
| # be counted if the Content-Length of an unchunked |
| # request exceeds the server's limit; it'll just be |
| # drained and discarded. |
| # |
| if ($chunked) { |
| if ($no_chunking) { |
| my $msg = 'Chunked upload not tested; ' |
| . 'not supported by this version of LWP'; |
| print "# $msg\n"; |
| skip $msg, 1; |
| } |
| else { |
| my ($req, $resp, $url); |
| $url = Apache::TestRequest::resolve_url('/apache/limits/'); |
| $req = HTTP::Request->new(GET => $url); |
| $req->content_type('text/plain'); |
| $req->header('X-Subtest' => $testnum); |
| $req->content(chunk_it($param)); |
| $resp = Apache::TestRequest::user_agent->request($req); |
| |
| # limit errors with chunked request bodies get |
| # 400 with 1.3, not 413 - see special chunked |
| # request handling in ap_get_client_block in 1.3 |
| |
| local $expected_rc = 400 if $goodbad eq 'fail' && |
| have_apache(1); |
| |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| } |
| } |
| else { |
| $resp = GET('/apache/limits/', content_type => 'text/plain', |
| content => $param, 'X-Subtest' => $testnum); |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| } |
| $testnum++; |
| } |
| } |
| elsif ($cond eq 'merged_fieldsize') { |
| print "# Testing LimitRequestFieldSize; should $goodbad\n"; |
| $resp = GET('/apache/limits/', 'X-Subtest' => $testnum, |
| 'X-overflow-field' => $param, |
| 'X-overflow-field' => $param); |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| $testnum++; |
| } |
| elsif ($cond eq 'fieldsize') { |
| print "# Testing LimitRequestFieldSize; should $goodbad\n"; |
| $resp = GET('/apache/limits/', 'X-Subtest' => $testnum, |
| 'X-overflow-field' => $param); |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| $testnum++; |
| } |
| elsif ($cond eq 'requestline') { |
| print "# Testing LimitRequestLine; should $goodbad\n"; |
| $resp = GET($param, 'X-Subtest' => $testnum); |
| ok t_cmp($resp->code, |
| $expected_rc, |
| "Test #$testnum"); |
| if ($resp->code != $expected_rc) { |
| print_response($resp); |
| } |
| $testnum++; |
| } |
| } |
| } |
| |
| sub chunk_it { |
| my $str = shift; |
| my $delay = shift; |
| |
| $delay = 1 unless defined $delay; |
| return sub { |
| select(undef, undef, undef, $delay) if $delay; |
| my $l = length($str); |
| return substr($str, 0, ($l > 102400 ? 102400 : $l), ""); |
| } |
| } |
| |
| sub set_chunking { |
| my ($setting) = @_; |
| $setting = $setting ? 1 : 0; |
| print "# Chunked transfer-encoding ", |
| ($setting ? "enabled" : "disabled"), "\n"; |
| Apache::TestRequest::user_agent(keep_alive => ($setting ? 1 : 0)); |
| } |
| |
| sub print_response { |
| my ($resp) = @_; |
| my $str = $resp->as_string; |
| $str =~ s:\n:\n# :gs; |
| print "# Server response:\n# $str\n"; |
| } |