| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package FU::MultipartFormData 1.4; |
|
2
|
1
|
|
|
1
|
|
90197
|
use v5.36; |
|
|
1
|
|
|
|
|
4
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use Carp 'confess'; |
|
|
1
|
|
|
|
|
14
|
|
|
|
1
|
|
|
|
|
69
|
|
|
4
|
1
|
|
|
1
|
|
551
|
use FU::Util 'utf8_decode'; |
|
|
1
|
|
|
|
|
14
|
|
|
|
1
|
|
|
|
|
2294
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
11
|
|
|
11
|
|
20
|
sub _arg($d) { $d =~ s{^"(.+)"$}{$1 =~ s/\\([\\"])/$1/rg}er } |
|
|
11
|
|
|
|
|
32
|
|
|
|
11
|
|
|
|
|
14
|
|
|
|
11
|
|
|
|
|
57
|
|
|
|
6
|
|
|
|
|
44
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
1
|
141188
|
sub parse($pkg, $header, $data) { |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
9
|
1
|
50
|
|
|
|
10
|
confess "Invalid multipart header '$header'" |
|
10
|
|
|
|
|
|
|
if $header !~ m{^multipart/form-data\s*;\s*boundary\s*=(.+)$}; |
|
11
|
1
|
|
|
|
|
6
|
my $boundary = _arg $1; |
|
12
|
1
|
50
|
|
|
|
7
|
confess "Invalid multipart boundary '$boundary'" if $boundary !~ /^[\x21-\x7e]+$/; |
|
13
|
1
|
|
|
|
|
7
|
utf8::encode($boundary); |
|
14
|
|
|
|
|
|
|
|
|
15
|
1
|
|
|
|
|
2
|
my @a; |
|
16
|
1
|
|
|
|
|
51
|
while ($data =~ m{--\Q$boundary\E(?:--\r\n|\r\n((?:.+\r\n)+)\r\n)}xg) { |
|
17
|
4
|
|
|
|
|
15
|
my $hdrs = $1; |
|
18
|
4
|
100
|
|
|
|
28
|
$a[$#a]{length} = $-[0] - 2 - $a[$#a]{start} if @a; |
|
19
|
4
|
100
|
|
|
|
13
|
if (!$hdrs) { |
|
20
|
1
|
50
|
|
|
|
5
|
confess "Trailing garbage" if pos $data != length $data; |
|
21
|
1
|
|
|
|
|
4
|
last; |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
|
|
24
|
3
|
|
|
|
|
36
|
my $d = bless { |
|
25
|
|
|
|
|
|
|
data => $data, |
|
26
|
|
|
|
|
|
|
start => pos $data, |
|
27
|
|
|
|
|
|
|
}, $pkg; |
|
28
|
|
|
|
|
|
|
|
|
29
|
3
|
50
|
|
|
|
28
|
confess "Missing content-disposition header" if $hdrs !~ /content-disposition:\s*form-data(.+)/i; |
|
30
|
3
|
|
|
|
|
8
|
my $v = $1; |
|
31
|
3
|
|
|
|
|
12
|
my $pvalue = qr/("(?:\\[\\"]|[^\\"\r\n]+)*"|[^\s;"]*)/; |
|
32
|
3
|
50
|
|
|
|
120
|
confess "Missing 'name' parameter" if $v !~ /;\s*name\s*=\s*$pvalue/; |
|
33
|
3
|
|
|
|
|
13
|
$d->{name} = utf8_decode _arg $1; |
|
34
|
3
|
100
|
|
|
|
126
|
$d->{filename} = utf8_decode _arg $1 if $v =~ /;\s*filename\s*=\s*$pvalue/; |
|
35
|
|
|
|
|
|
|
|
|
36
|
3
|
50
|
|
|
|
219
|
if ($hdrs =~ /content-type:\s*$pvalue(?:\s*;\s*charset\s*=\s*$pvalue)?/i) { |
|
37
|
3
|
|
|
|
|
12
|
$d->{mime} = utf8_decode _arg $1; |
|
38
|
3
|
100
|
|
|
|
16
|
$d->{charset} = utf8_decode _arg $2 if $2; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
3
|
|
|
|
|
47
|
push @a, $d; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
1
|
50
|
33
|
|
|
8
|
confess "Missing end-of-data marker" if @a && !defined $a[$#a]{length}; |
|
43
|
|
|
|
|
|
|
\@a |
|
44
|
1
|
|
|
|
|
5
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
3
|
|
|
3
|
1
|
1249
|
sub name { $_[0]{name} } |
|
47
|
3
|
|
|
3
|
1
|
19
|
sub filename { $_[0]{filename} } |
|
48
|
3
|
|
|
3
|
1
|
32
|
sub mime { $_[0]{mime} } |
|
49
|
3
|
|
|
3
|
1
|
15
|
sub charset { $_[0]{charset} } |
|
50
|
3
|
|
|
3
|
1
|
16
|
sub length { $_[0]{length} } |
|
51
|
|
|
|
|
|
|
|
|
52
|
9
|
|
|
9
|
1
|
21
|
sub substr($o,$off,$len=undef) { |
|
|
9
|
|
|
|
|
20
|
|
|
|
9
|
|
|
|
|
12
|
|
|
|
9
|
|
|
|
|
17
|
|
|
|
9
|
|
|
|
|
13
|
|
|
53
|
9
|
100
|
|
|
|
50
|
$off += $o->{length} if $off < 0; |
|
54
|
9
|
100
|
|
|
|
27
|
$off = 0 if $off < 0; |
|
55
|
9
|
50
|
|
|
|
28
|
$off = $o->{length} if $off > $o->{length}; |
|
56
|
|
|
|
|
|
|
|
|
57
|
9
|
|
66
|
|
|
39
|
$len //= $o->{length} - $off; |
|
58
|
9
|
100
|
|
|
|
23
|
$len += $o->{length} - 1 if $len < 0; |
|
59
|
9
|
50
|
|
|
|
22
|
$len = 0 if $len < 0; |
|
60
|
9
|
100
|
|
|
|
26
|
$len = $o->{length} - $off if $len > $o->{length} - $off; |
|
61
|
|
|
|
|
|
|
|
|
62
|
9
|
|
|
|
|
72
|
substr $o->{data}, $o->{start} + $off, $len; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
3
|
|
|
3
|
1
|
14
|
sub data { $_[0]->substr(0) } |
|
66
|
0
|
|
|
0
|
1
|
|
sub value { utf8_decode $_[0]->data } |
|
67
|
|
|
|
|
|
|
|
|
68
|
0
|
|
|
0
|
1
|
|
sub syswrite($o, $fh) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
69
|
0
|
|
|
|
|
|
my $off = $o->{start}; |
|
70
|
0
|
|
|
|
|
|
my $end = $o->{start} + $o->{length}; |
|
71
|
0
|
|
|
|
|
|
while ($off < $end) { |
|
72
|
0
|
|
|
|
|
|
my $r = syswrite $fh, $o->{data}, $end-$off, $off; |
|
73
|
0
|
0
|
|
|
|
|
return if !defined $r; |
|
74
|
0
|
|
|
|
|
|
$off += $r; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
0
|
|
|
|
|
|
$o->{length}; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
0
|
|
|
0
|
1
|
|
sub save($o, $fn) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
80
|
0
|
0
|
|
|
|
|
open my $F, '>', $fn or confess "Error opening '$fn': $!"; |
|
81
|
0
|
0
|
|
|
|
|
defined $o->syswrite($F) or confess "Error writing to '$fn': $!"; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
0
|
|
|
0
|
1
|
|
sub describe($o) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
my $head = eval { utf8_decode $o->substr(0, 100) }; |
|
|
0
|
|
|
|
|
|
|
|
86
|
0
|
0
|
0
|
|
|
|
if (defined $head && $head =~ /\n/) { |
|
|
|
0
|
0
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
($head) = split /\n/, $head, 2; |
|
88
|
0
|
|
|
|
|
|
$head .= '...'; |
|
89
|
|
|
|
|
|
|
} elsif (defined $head && $o->{length} > 100) { |
|
90
|
0
|
|
|
|
|
|
$head .= '...'; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
$o->{name}.': '.join ' ', |
|
93
|
|
|
|
|
|
|
$o->{filename} ? "filename=$o->{filename}" : (), |
|
94
|
|
|
|
|
|
|
$o->{mime} ? "mime=$o->{mime}" : (), |
|
95
|
0
|
0
|
|
|
|
|
$o->{charset} ? "charset=$o->{charset}" : (), |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
"length=$o->{length}", |
|
97
|
|
|
|
|
|
|
defined $head ? "value=$head" : (); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1; |
|
101
|
|
|
|
|
|
|
__END__ |