File Coverage

blib/lib/Plack/Middleware/LimitRequest.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::LimitRequest;
2              
3 1     1   374 use strict;
  1         1  
  1         31  
4 1     1   4 use warnings;
  1         1  
  1         21  
5 1     1   14 use 5.008_001;
  1         2  
  1         30  
6 1     1   3 use Carp;
  1         1  
  1         66  
7 1     1   390 use parent qw(Plack::Middleware);
  1         238  
  1         4  
8             use Plack::Util::Accessor qw(body fields field_size line);
9              
10             our $VERSION = '0.01';
11              
12             sub prepare_app {
13             my $self = shift;
14             $self->body(0) if ! defined $self->body;
15             $self->fields(100) if ! defined $self->fields;
16             $self->field_size(8190) if ! defined $self->field_size;
17             $self->line(8190) if ! defined $self->line;
18             }
19              
20             sub call {
21             my($self, $env) = @_;
22              
23             # HTTP request body size limitation
24             if (my $body_limit = $self->body) {
25             if (my $content_length = $env->{CONTENT_LENGTH}) {
26             if ($content_length > $body_limit) {
27             return $self->handle_error(413 => 'Entity Too Large');
28             }
29             }
30             }
31              
32             # HTTP request line length limitation
33             if (my $line_limit = $self->line) {
34             my $total = 0;
35             for my $env_key (qw(REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL)) {
36             $total += length $env->{$env_key};
37             if ($env_key ne 'SERVER_PROTOCOL') { # append a white space
38             ++$total;
39             }
40             if ($total > $line_limit) {
41             return $self->handle_error(414 => 'Request-URI Too Large');
42             }
43             }
44             }
45              
46             # HTTP request header field number and field size limitation
47             my $limit_fields = $self->fields;
48             my $limit_field_size = $self->field_size;
49              
50             if ($limit_fields or $limit_field_size) {
51             my $field_count = 1; # includes the request line
52             for my $env_key (keys %$env) {
53             next if $env_key !~ /^(?:HTTP_\w+|CONTENT_(?:TYPE|LENGTH))$/;
54             ++$field_count;
55             if ($limit_fields && $field_count > $limit_fields) {
56             return $self->handle_error(400 => 'Bad Request');
57             }
58             if ($limit_field_size) {
59             (my $field_name = $env_key) =~ s/^HTTP_//;
60             # "2" means length of separator ": "
61             my $field_size =
62             length($field_name) + 2 + length($env->{$env_key});
63             if ($field_size > $limit_field_size) {
64             return $self->handle_error(400 => 'Bad Request');
65             }
66             }
67             }
68             }
69              
70             return $self->app->($env);
71             }
72              
73             sub handle_error {
74             my($self, $code, $body) = @_;
75             return [
76             $code,
77             [
78             'Content-Type' => 'text/plain',
79             'Content-Length' => length $body,
80             ],
81             [ $body ],
82             ];
83             }
84              
85             1;
86             __END__