File Coverage

blib/lib/Perlbal/Plugin/MaxContentLength.pm
Criterion Covered Total %
statement 15 34 44.1
branch 0 12 0.0
condition n/a
subroutine 5 9 55.5
pod 0 3 0.0
total 20 58 34.4


line stmt bran cond sub pod time code
1             package Perlbal::Plugin::MaxContentLength;
2              
3             =head1 NAME
4              
5             Perlbal::Plugin::MaxContentLength - Reject large requests
6              
7             =head1 SYNOPSIS
8              
9             LOAD MaxContentLength
10             CREATE SERVICE cgilike
11             # define a service...
12             SET max_content_length = 100000
13             SET plugins = MaxContentLength
14             ENABLE cgilike
15              
16             =head1 DESCRIPTION
17              
18             This module rejects requests that are larger than a configured limit. If a
19             request bears a Content-Length header whose value exceeds the
20             max_content_length value, the request will be rejected with a 413 "Request
21             Entity Too Large" error.
22              
23             =head1 AUTHOR
24              
25             Adam Thomason, Eathomason@sixapart.comE
26              
27             =head1 COPYRIGHT AND LICENSE
28              
29             Copyright 2008 Six Apart Ltd.
30              
31             This module is part of the Perlbal distribution, and as such can be distributed
32             under the same licence terms as the rest of Perlbal.
33              
34             =cut
35              
36 1     1   4369 use strict;
  1         3  
  1         158  
37 1     1   8 use warnings;
  1         3  
  1         40  
38              
39 1     1   6 use Perlbal;
  1         3  
  1         86  
40              
41             sub load {
42 0     0 0   Perlbal::Service::add_tunable(
43             max_content_length => {
44             check_role => '*',
45             check_type => 'int',
46             des => "maximum Content-Length allowed, in bytes. 0 for no limit",
47             default => 0,
48             },
49             );
50 0           return 1;
51             }
52              
53 1     1   7 use constant HANDLE_REQUEST => 0;
  1         2  
  1         268  
54 1     1   7 use constant IGNORE_REQUEST => 1;
  1         2  
  1         563  
55              
56             sub register {
57 0     0 0   my ($class, $svc) = @_;
58              
59 0           my $cfg = $svc->{extra_config};
60 0 0         return unless $cfg;
61              
62             $svc->register_hook('MaxContentLength', 'start_http_request' => sub {
63 0     0     my $client = shift;
64 0 0         return IGNORE_REQUEST unless $client;
65              
66             # allow request if max is disabled
67 0 0         return HANDLE_REQUEST unless $cfg->{max_content_length};
68              
69 0           my $headers = $client->{req_headers};
70 0 0         return HANDLE_REQUEST unless $headers;
71              
72             # allow requests which don't have a Content-Length header
73 0           my $length = $headers->header('content-length');
74 0 0         return HANDLE_REQUEST unless $length;
75              
76             # allow requests under the cap
77 0 0         return HANDLE_REQUEST if $length <= $cfg->{max_content_length};
78              
79 0           $client->send_response(413, "Content too long.\n");
80 0           return IGNORE_REQUEST;
81 0           });
82             }
83              
84             sub unregister {
85 0     0 0   my ($class, $svc) = @_;
86              
87 0           $svc->unregister_hooks('MaxContentLength');
88 0           return 1;
89             }
90              
91             1;