/
Dechunk.pm
83 lines (58 loc) · 1.86 KB
/
Dechunk.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package Plack::Middleware::Dechunk;
use strict;
use parent qw(Plack::Middleware);
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);
}
$self->app->($env);
}
sub dechunk_input {
my($self, $env) = @_;
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);
while ( $chunk_buffer =~ s/^(([0-9a-fA-F]+).*\015\012)// ) {
my $trailer = $1;
my $chunk_len = hex $2;
if ($chunk_len == 0) {
last DECHUNK;
} elsif (length $chunk_buffer < $chunk_len) {
$chunk_buffer = $trailer . $chunk_buffer;
last;
}
$buffer->print(substr $chunk_buffer, 0, $chunk_len, '');
$chunk_buffer =~ s/^\015\012//;
$length += $chunk_len;
}
last unless $read && $read > 0;
}
delete $env->{HTTP_TRANSFER_ENCODING};
$env->{CONTENT_LENGTH} = $length;
$env->{'psgi.input'} = $buffer->rewind;
}
1;
__END__
=head1 NAME
Plack::Middleware::Dechunk - Decode chunked (TE: chunked) request body
=head1 SYNOPSIS
# This should be used in Servers as a library
=head1 DESCRIPTION
This middleware checks if an incoming request is chunked, and in that
case decodes the request body and buffers the whole output, and sets
the IO (either with PerlIO or with a temp filehandle) to
C<psgi.input>. It also sets I<Content-Length> header so your
application can work transparently.
=head1 AUTHOR
Tatsuhiko Miyagawa
=head1 SEE ALSO
L<HTTP::Body>
=cut