Skip to content

Commit

Permalink
added max_buffer_size attribute and is_limit_exceeded method to Mojo:…
Browse files Browse the repository at this point in the history
…:Content
  • Loading branch information
kraih committed Oct 25, 2012
1 parent 32d94ef commit e0af13d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Changes
Expand Up @@ -2,6 +2,8 @@
3.52 2012-10-26
- Added boolean shortcut support to Mojo::JSON.
- Added escape attribute to Mojo::Template. (jberger)
- Added max_buffer_size attribute to Mojo::Content.
- Added is_limit_exceeded method to Mojo::Content.
- Improved documentation.
- Improved tests.

Expand Down
23 changes: 22 additions & 1 deletion lib/Mojo/Content.pm
Expand Up @@ -5,7 +5,8 @@ use Carp 'croak';
use Mojo::Headers;

has [qw(auto_relax relaxed skip_body)];
has headers => sub { Mojo::Headers->new };
has headers => sub { Mojo::Headers->new };
has max_buffer_size => sub { $ENV{MOJO_MAX_BUFFER_SIZE} || 262144 };
has max_leftover_size => sub { $ENV{MOJO_MAX_LEFTOVER_SIZE} || 262144 };

sub body_contains {
Expand Down Expand Up @@ -79,6 +80,8 @@ sub is_dynamic {

sub is_finished { (shift->{state} // '') eq 'finished' }

sub is_limit_exceeded { !!shift->{limit} }

sub is_multipart {undef}

sub is_parsing_body { (shift->{state} // '') eq 'body' }
Expand Down Expand Up @@ -268,6 +271,10 @@ sub _parse_chunked {
# Trailing headers
$self->_parse_chunked_trailing_headers
if ($self->{chunk_state} // '') eq 'trailing_headers';

# Check buffer size
$self->{limit} = 1
if length($self->{pre_buffer} // '') > $self->max_buffer_size;
}

sub _parse_chunked_trailing_headers {
Expand Down Expand Up @@ -407,6 +414,14 @@ Try to detect when relaxed parsing is necessary.
Content headers, defaults to a L<Mojo::Headers> object.
=head2 C<max_buffer_size>
my $size = $content->max_buffer_size;
$content = $content->max_buffer_size(1024);
Maximum size in bytes of buffer for content parser, defaults to the value of
the C<MOJO_MAX_BUFFER_SIZE> environment variable or C<262144>.
=head2 C<max_leftover_size>
my $size = $content->max_leftover_size;
Expand Down Expand Up @@ -528,6 +543,12 @@ working.
Check if parser is finished.
=head2 C<is_limit_exceeded>
my $success = $content->is_limit_exceeded;
Check if buffer has exceeded C<max_buffer_size>.
=head2 C<is_multipart>
my $false = $content->is_multipart;
Expand Down
4 changes: 4 additions & 0 deletions lib/Mojo/Content/MultiPart.pm
Expand Up @@ -199,6 +199,10 @@ sub _read {
last unless $self->_parse_multipart_body($boundary);
}
}

# Check buffer size
$self->{limit} = 1
if length($self->{multipart} // '') > $self->max_buffer_size;
}

1;
Expand Down
4 changes: 4 additions & 0 deletions lib/Mojo/Message.pm
Expand Up @@ -224,6 +224,10 @@ sub parse {
return $self->error('Maximum line size exceeded', 431)
if $self->headers->is_limit_exceeded;

# Check buffer size
return $self->error('Maximum buffer size exceeded', 400)
if $self->content->is_limit_exceeded;

# Progress
$self->emit('progress');

Expand Down
40 changes: 39 additions & 1 deletion t/mojo/response.t
@@ -1,6 +1,6 @@
use Mojo::Base -strict;

use Test::More tests => 370;
use Test::More tests => 386;

use Mojo::Asset::File;
use Mojo::Content::Single;
Expand Down Expand Up @@ -296,6 +296,44 @@ is $res->message, 'Request Entity Too Large', 'right message';
is $res->version, '1.1', 'right version';
is $res->headers->content_length, undef, 'right "Content-Length" value';

# Parse HTTP 1.1 chunked response (exceeding limit)
{
local $ENV{MOJO_MAX_BUFFER_SIZE} = 12;
$res = Mojo::Message::Response->new;
is $res->content->max_buffer_size, 12, 'right size';
$res->parse("HTTP/1.1 200 OK\x0d\x0a");
$res->parse("Content-Type: text/plain\x0d\x0a");
$res->parse("Transfer-Encoding: chunked\x0d\x0a\x0d\x0a");
$res->parse('4' x 1000);
ok $res->is_finished, 'response is finished';
is(($res->error)[0], 'Maximum buffer size exceeded', 'right error');
is(($res->error)[1], 400, 'right status');
is $res->code, 200, 'right status';
is $res->message, 'OK', 'right message';
is $res->version, '1.1', 'right version';
is $res->headers->content_type, 'text/plain', 'right "Content-Type" value';
}

# Parse HTTP 1.1 multipart response (exceeding limit)
{
local $ENV{MOJO_MAX_BUFFER_SIZE} = 12;
$res = Mojo::Message::Response->new;
is $res->content->max_buffer_size, 12, 'right size';
$res->parse("HTTP/1.1 200 OK\x0d\x0a");
$res->parse("Content-Length: 420\x0d\x0a");
$res->parse('Content-Type: multipart/form-data; bo');
$res->parse("undary=----------0xKhTmLbOuNdArY\x0d\x0a\x0d\x0a");
$res->parse(4 x 420);
ok $res->is_finished, 'response is finished';
is(($res->error)[0], 'Maximum buffer size exceeded', 'right error');
is(($res->error)[1], 400, 'right status');
is $res->code, 200, 'right status';
is $res->message, 'OK', 'right message';
is $res->version, '1.1', 'right version';
ok $res->headers->content_type =~ m!multipart/form-data!,
'right "Content-Type" value';
}

# Parse HTTP 1.1 chunked response
$res = Mojo::Message::Response->new;
$res->parse("HTTP/1.1 500 Internal Server Error\x0d\x0a");
Expand Down

0 comments on commit e0af13d

Please sign in to comment.