Skip to content

Commit

Permalink
Use TempBuffer in Dechunk middleware.
Browse files Browse the repository at this point in the history
TempBuffer now added Auto backend, which begins with PerlIO but
switches to File when the size exceeds the max limit, which may have a
little overhead but suitable for chunked requests.
  • Loading branch information
miyagawa committed Feb 9, 2010
1 parent 76cc8f3 commit 1b2e27e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 13 deletions.
17 changes: 9 additions & 8 deletions lib/Plack/Middleware/Dechunk.pm
@@ -1,13 +1,13 @@
package Plack::Middleware::Dechunk;
use strict;
no warnings;
use parent qw(Plack::Middleware);

use constant CHUNK_SIZE => 1024;# * 32;
use Plack::TempBuffer;
use constant CHUNK_SIZE => 1024 * 32;

sub call {
my($self, $env) = @_;

no warnings;
if ( $env->{HTTP_TRANSFER_ENCODING} eq 'chunked'
&& ($env->{REQUEST_METHOD} eq 'POST' || $env->{REQUEST_METHOD} eq 'PUT')) {
$self->dechunk_input($env);
Expand All @@ -19,18 +19,19 @@ sub call {
sub dechunk_input {
my($self, $env) = @_;

my $chunk_buffer = '';
my($body, $length);
my $buffer = Plack::TempBuffer->new;
my $chunk_buffer;
my $length;

DECHUNK:
while (1) {
my $read = $env->{'psgi.input'}->read($chunk_buffer, CHUNK_SIZE, length $chunk_buffer);
my $read = $env->{'psgi.input'}->read(my $chunk_buffer, CHUNK_SIZE, length $chunk_buffer);

while ( $chunk_buffer =~ s/^([0-9a-fA-F]+).*\015\012// ) {
my $chunk_len = hex $1;
last DECHUNK if $chunk_len == 0;

$body .= substr $chunk_buffer, 0, $chunk_len, '';
$buffer->print(substr $chunk_buffer, 0, $chunk_len, '');
$chunk_buffer =~ s/^\015\012//;

$length += $chunk_len;
Expand All @@ -41,7 +42,7 @@ sub dechunk_input {

delete $env->{HTTP_TRANSFER_ENCODING};
$env->{CONTENT_LENGTH} = $length;
$env->{'psgi.input'} = do { open my $input, "<", \$body; $input };
$env->{'psgi.input'} = $buffer->rewind;
}

1;
Expand Down
25 changes: 21 additions & 4 deletions lib/Plack/TempBuffer.pm
Expand Up @@ -11,15 +11,30 @@ sub new {

# $MaxMemoryBufferSize = 0 -> Always temp file
# $MaxMemoryBufferSize = -1 -> Always PerlIO
if ($length && $MaxMemoryBufferSize >= 0 && $length > $MaxMemoryBufferSize) {
Plack::Util::load_class('File', $class)->new($length);
my $backend;
if ($MaxMemoryBufferSize < 0) {
$backend = "PerlIO";
} elsif ($MaxMemoryBufferSize == 0) {
$backend = "File";
} elsif (!$length) {
$backend = "Auto";
} elsif ($length > $MaxMemoryBufferSize) {
$backend = "File";
} else {
Plack::Util::load_class('PerlIO', $class)->new;
$backend = "PerlIO";
}

$class->create($backend, $length, $MaxMemoryBufferSize);
}

sub create {
my($class, $backend, $length, $max) = @_;
Plack::Util::load_class($backend, $class)->new($length, $max);
}

sub print;
sub rewind;
sub size;

1;

Expand All @@ -33,7 +48,9 @@ Plack::TempBuffer - temporary buffer to save bytes
my $buf = Plack::TempBuffer->new($length);
$buf->print($bytes);
my $fh = $buf->rewind;
my $size = $buf->size;
my $fh = $buf->rewind;
=head1 DESCRIPTION
Expand Down
34 changes: 34 additions & 0 deletions lib/Plack/TempBuffer/Auto.pm
@@ -0,0 +1,34 @@
package Plack::TempBuffer::Auto;
use strict;
use parent 'Plack::TempBuffer';

sub new {
my($class, undef, $max_memory_size) = @_;
bless {
_buffer => Plack::TempBuffer->create('PerlIO'),
_max => $max_memory_size,
}, $class;
}

sub print {
my $self = shift;
$self->{_buffer}->print(@_);

if ($self->{_buffer}->size > $self->{_max}) {
my $buf = $self->{_buffer}->{buffer};
$self->{_buffer} = Plack::TempBuffer->create('File'),
$self->{_buffer}->print($buf);
}
}

sub size {
my $self = shift;
$self->{_buffer}->size;
}

sub rewind {
my $self = shift;
$self->{_buffer}->rewind;
}

1;
6 changes: 6 additions & 0 deletions lib/Plack/TempBuffer/File.pm
Expand Up @@ -18,6 +18,12 @@ sub print {
$self->{fh}->print(@_);
}

sub size {
my $self = shift;
$self->{fh}->flush;
-s $self->{fh};
}

sub rewind {
my $self = shift;
$self->{fh}->seek(0, 0);
Expand Down
5 changes: 5 additions & 0 deletions lib/Plack/TempBuffer/PerlIO.pm
Expand Up @@ -12,6 +12,11 @@ sub print {
$self->{buffer} .= "@_";
}

sub size {
my $self = shift;
length $self->{buffer};
}

sub rewind {
my $self = shift;
my $buffer = $self->{buffer};
Expand Down
16 changes: 15 additions & 1 deletion t/Plack-TempBuffer/print.t
Expand Up @@ -3,18 +3,32 @@ use Test::More;
use Plack::TempBuffer;

{
my $b = Plack::TempBuffer->new;
my $b = Plack::TempBuffer->new(-1);
$b->print("foo");
is $b->size, 3;
my $fh = $b->rewind;
is do { local $/; <$fh> }, 'foo';
$fh->seek(0, 0);
}

{
local $Plack::TempBuffer::MaxMemoryBufferSize = 12;
my $b = Plack::TempBuffer->new;
is $b->size, 0;
$b->print("foo") for 1..5;
is $b->size, 15;
my $fh = $b->rewind;
isa_ok $fh, 'IO::File';
is do { local $/; <$fh> }, ('foo' x 5);
}

{
local $Plack::TempBuffer::MaxMemoryBufferSize = 0;
my $b = Plack::TempBuffer->new(3);
$b->print("foo\n");
is $b->size, 4;
my $fh = $b->rewind;
isa_ok $fh, 'IO::File';
is do { local $/; <$fh> }, "foo\n";
}

Expand Down

0 comments on commit 1b2e27e

Please sign in to comment.