/usr/share/perl5/Web/Dispatch/ParamParser.pm is in libweb-simple-perl 0.031-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | package Web::Dispatch::ParamParser;
use strict;
use warnings FATAL => 'all';
use Encode 'decode_utf8';
sub UNPACKED_QUERY () { __PACKAGE__.'.unpacked_query' }
sub UNPACKED_BODY () { __PACKAGE__.'.unpacked_body' }
sub UNPACKED_BODY_OBJECT () { __PACKAGE__.'.unpacked_body_object' }
sub UNPACKED_UPLOADS () { __PACKAGE__.'.unpacked_uploads' }
sub ORIG_ENV () { 'Web::Dispatch.original_env' }
sub get_unpacked_query_from {
return ($_[0]->{+ORIG_ENV}||$_[0])->{+UNPACKED_QUERY} ||= do {
_unpack_params($_[0]->{QUERY_STRING})
};
}
sub get_unpacked_body_from {
return ($_[0]->{+ORIG_ENV}||$_[0])->{+UNPACKED_BODY} ||= do {
my $ct = lc($_[0]->{CONTENT_TYPE}||'');
if (!$_[0]->{CONTENT_LENGTH}) {
{}
} elsif (index($ct, 'application/x-www-form-urlencoded') >= 0) {
$_[0]->{'psgi.input'}->read(my $buf, $_[0]->{CONTENT_LENGTH});
_unpack_params($buf);
} elsif (index($ct, 'multipart/form-data') >= 0) {
my $p = get_unpacked_body_object_from($_[0])->param;
# forcible arrayification (functional, $p does not belong to us,
# do NOT replace this with a side-effect ridden "simpler" version)
+{
map +(ref($p->{$_}) eq 'ARRAY'
? ($_ => $p->{$_})
: ($_ => [ $p->{$_} ])
), keys %$p
};
} else {
{}
}
};
}
sub get_unpacked_body_object_from {
# we may have no object at all - so use a single element arrayref for ||=
return (($_[0]->{+ORIG_ENV}||$_[0])->{+UNPACKED_BODY_OBJECT} ||= do {
if (!$_[0]->{CONTENT_LENGTH}) {
[ undef ]
} elsif (index(lc($_[0]->{CONTENT_TYPE}||''),'multipart/form-data')==-1) {
[ undef ]
} else {
[ _make_http_body($_[0]) ]
}
})->[0];
}
sub get_unpacked_uploads_from {
$_[0]->{+UNPACKED_UPLOADS} ||= do {
require Web::Dispatch::Upload; require HTTP::Headers;
my ($final, $reason) = (
{}, "field %s exists with value %s but body was not multipart/form-data"
);
if (my $body = get_unpacked_body_object_from($_[0])) {
my $u = $body->upload;
$reason = "field %s exists with value %s but was not an upload";
foreach my $k (keys %$u) {
foreach my $v (ref($u->{$k}) eq 'ARRAY' ? @{$u->{$k}} : $u->{$k}) {
push(@{$final->{$k}||=[]}, Web::Dispatch::Upload->new(
%{$v},
headers => HTTP::Headers->new($v->{headers})
));
}
}
}
my $b = get_unpacked_body_from($_[0]);
foreach my $k (keys %$b) {
next if $final->{$k};
foreach my $v (@{$b->{$k}}) {
next unless $v;
push(@{$final->{$k}||=[]}, Web::Dispatch::NotAnUpload->new(
filename => $v,
reason => sprintf($reason, $k, $v)
));
}
}
$final;
};
}
{
# shamelessly stolen from HTTP::Body::UrlEncoded by Christian Hansen
my $DECODE = qr/%([0-9a-fA-F]{2})/;
my %hex_chr;
foreach my $num ( 0 .. 255 ) {
my $h = sprintf "%02X", $num;
$hex_chr{ lc $h } = $hex_chr{ uc $h } = chr $num;
}
sub _unpack_params {
my %unpack;
(my $params = $_[0]) =~ s/\+/ /g;
my ($name, $value);
foreach my $pair (split(/[&;](?:\s+)?/, $params)) {
$value = 1 unless (($name, $value) = split(/=/, $pair, 2)) == 2;
s/$DECODE/$hex_chr{$1}/gs for ($name, $value);
$_ = decode_utf8 $_ for ($name, $value);
push(@{$unpack{$name}||=[]}, $value);
}
\%unpack;
}
}
{
# shamelessly stolen from Plack::Request by miyagawa
sub _make_http_body {
# Can't actually do this yet, since Plack::Request deletes the
# header structure out of the uploads in its copy of the body.
# I suspect I need to supply miyagawa with a failing test.
#if (my $plack_body = $_[0]->{'plack.request.http.body'}) {
# # Plack already constructed one; probably wasteful to do it again
# return $plack_body;
#}
require HTTP::Body;
my $body = HTTP::Body->new(@{$_[0]}{qw(CONTENT_TYPE CONTENT_LENGTH)});
$body->cleanup(1);
my $spin = 0;
my $input = $_[0]->{'psgi.input'};
my $cl = $_[0]->{CONTENT_LENGTH};
while ($cl) {
$input->read(my $chunk, $cl < 8192 ? $cl : 8192);
my $read = length $chunk;
$cl -= $read;
$body->add($chunk);
if ($read == 0 && $spin++ > 2000) {
require Carp;
Carp::croak("Bad Content-Length: maybe client disconnect? ($cl bytes remaining)");
}
}
return $body;
}
}
1;
|