File Coverage

blib/lib/CGI/Easy/Util.pm
Criterion Covered Total %
statement 147 157 93.6
branch 44 56 78.5
condition 4 6 66.6
subroutine 28 28 100.0
pod 6 9 66.6
total 229 256 89.4


line stmt bran cond sub pod time code
1             package CGI::Easy::Util;
2 3     3   38 use 5.010001;
  3         8  
3 3     3   12 use warnings;
  3         3  
  3         54  
4 3     3   11 use strict;
  3         4  
  3         48  
5 3     3   10 use utf8;
  3         3  
  3         18  
6 3     3   62 use Carp;
  3         4  
  3         173  
7              
8             our $VERSION = 'v2.0.1';
9              
10 3     3   1157 use Export::Attrs;
  3         19647  
  3         18  
11 3     3   1272 use URI::Escape qw( uri_unescape uri_escape_utf8 );
  3         3751  
  3         244  
12              
13              
14             sub date_http :Export {
15 6     6 1 11 my ($tick) = @_;
16 6         13 return _date($tick, 'http');
17 3     3   17 }
  3         6  
  3         13  
18              
19             sub date_cookie :Export {
20 9     9 1 14 my ($tick) = @_;
21 9         14 return _date($tick, 'cookie');
22 3     3   638 }
  3         5  
  3         22  
23              
24             sub _date {
25 15     15   21 my ($tick, $format) = @_;
26 15 100       28 my $sp = $format eq 'cookie' ? q{-} : q{ };
27 15         54 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime $tick;
28 15         26 my $wkday = qw(Sun Mon Tue Wed Thu Fri Sat)[$wday];
29 15         20 my $month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[$mon];
30 15         74 return sprintf "%s, %02d$sp%s$sp%s %02d:%02d:%02d GMT",
31             $wkday, $mday, $month, $year+1900, $hour, $min, $sec; ## no critic(ProhibitMagicNumbers)
32             }
33              
34             sub make_cookie :Export {
35 12     12 1 15 my ($opt) = @_;
36 12 50       22 return q{} if !defined $opt->{name};
37              
38 12         14 my $name = $opt->{name};
39 12 50       21 my $value = defined $opt->{value} ? $opt->{value} : q{};
40 12         15 my $domain = $opt->{domain};
41 12 50       17 my $path = defined $opt->{path} ? $opt->{path} : q{/}; # IE require it
42             my $expires = defined $opt->{expires} && $opt->{expires} =~ /\A\d+\z/xms ?
43 12 100 66     62 date_cookie($opt->{expires}) : $opt->{expires};
44 12         17 my $set_cookie = 'Set-Cookie: ';
45 12         22 $set_cookie .= uri_escape_utf8($name) . q{=} . uri_escape_utf8($value);
46 12 100       374 $set_cookie .= "; domain=$domain" if defined $domain; ## no critic(ProhibitPostfixControls)
47 12         16 $set_cookie .= "; path=$path";
48 12 100       22 $set_cookie .= "; expires=$expires" if defined $expires;## no critic(ProhibitPostfixControls)
49 12 50       19 $set_cookie .= '; secure' if $opt->{secure}; ## no critic(ProhibitPostfixControls)
50 12         14 $set_cookie .= "\r\n";
51 12         40 return $set_cookie;
52 3     3   1315 }
  3         6  
  3         9  
53              
54             sub uri_unescape_plus :Export {
55 112     112 1 149 my ($s) = @_;
56 112         242 $s =~ s/[+]/ /xmsg;
57 112         156 return uri_unescape($s);
58 3     3   556 }
  3         5  
  3         20  
59              
60             sub burst_urlencoded :Export {
61 38     38 1 58 my ($buffer) = @_;
62 38         42 my %param;
63 38 50       54 if (defined $buffer) {
64 38         6248 foreach my $pair (split /[&;]/xms, $buffer) {
65 49         3323 my ($name, $data) = split /=/xms, $pair, 2;
66 49 50       118 $name = !defined $name ? q{} : uri_unescape_plus($name);
67 49 100       584 $data = !defined $data ? q{} : uri_unescape_plus($data);
68 49         330 push @{ $param{$name} }, $data;
  49         2668  
69             }
70             }
71 38         101 return \%param;
72 3     3   875 }
  3         11  
  3         13  
73              
74             # This function derived from CGI::Minimal (1.29) by
75             # Benjamin Franz
76             # Copyright (c) Benjamin Franz. All rights reserved.
77             sub burst_multipart :Export {
78 2     2 1 12 my ($buffer, $bdry) = @_;
79              
80             # Special case boundaries causing problems with 'split'
81 2 50       9 if ($bdry =~ m{[^A-Za-z0-9',-./:=]}ms) { ## no critic (ProhibitEnumeratedClasses)
82 0         0 my $nbdry = $bdry;
83 0         0 $nbdry =~ s/([^A-Za-z0-9',-.\/:=])/ord($1)/msge;## no critic (ProhibitEnumeratedClasses)
  0         0  
84 0         0 my $quoted_boundary = quotemeta $nbdry;
85 0         0 while ($buffer =~ m/$quoted_boundary/ms) {
86 0         0 $nbdry .= chr(65 + int rand 25); ## no critic (ProhibitParensWithBuiltins, ProhibitMagicNumbers)
87 0         0 $quoted_boundary = quotemeta $nbdry;
88             }
89 0         0 my $old_boundary = quotemeta $bdry;
90 0         0 $buffer =~ s/$old_boundary/$nbdry/msg;
91 0         0 $bdry = $nbdry;
92             }
93              
94 2         6 $bdry = "--$bdry(--)?\r\n";
95 2         52 my @pairs = split /$bdry/ms, $buffer;
96              
97 2         5 my (%param, %filename, %mimetype);
98 2         6 foreach my $pair (@pairs) {
99 16 100       27 next if !defined $pair;
100 10         12 chop $pair; # Trailing \015
101 10         10 chop $pair; # Trailing \012
102 10 50       18 last if $pair eq q{--};
103 10 100       17 next if !$pair;
104              
105 6         21 my ($header, $data) = split /\r\n\r\n/ms, $pair, 2;
106              
107             # parse the header
108 6         17 $header =~ s/\r\n/\n/msg;
109 6         13 my @headerlines = split /\n/ms, $header;
110 6         7 my ($name, $filename, $mimetype);
111              
112 6         9 foreach my $headfield (@headerlines) {
113 8         17 my ($fname, $fdata) = split /: /ms, $headfield, 2;
114 8 100       19 if (lc $fname eq 'content-type') {
115 2         2 $mimetype = $fdata;
116             }
117 8 100       15 if (lc $fname eq 'content-disposition') {
118 6         13 my @dispositionlist = split /; /ms, $fdata;
119 6         9 foreach my $dispitem (@dispositionlist) {
120 14 100       23 next if $dispitem eq 'form-data';
121 8         14 my ($dispfield,$dispdata) = split /=/ms, $dispitem, 2;
122 8         21 $dispdata =~ s/\A\"//ms;
123 8         19 $dispdata =~ s/\"\z//ms;
124 8 100       15 if ($dispfield eq 'name') {
125 6         9 $name = $dispdata;
126             }
127 8 100       17 if ($dispfield eq 'filename') {
128 2         4 $filename = $dispdata;
129             }
130             }
131             }
132             }
133 6 50       11 next if !defined $name;
134 6 50       8 next if !defined $data;
135              
136 6         7 push @{ $param{$name} }, $data;
  6         14  
137 6         14 push @{ $filename{$name} }, $filename;
  6         17  
138 6         7 push @{ $mimetype{$name} }, $mimetype;
  6         18  
139             }
140 2         8 return (\%param, \%filename, \%mimetype);
141 3     3   1787 }
  3         5  
  3         17  
142              
143              
144             ### Unrelated to CGI, and thus internal/undocumented
145              
146             sub _quote {
147 10     10   14 my ($s) = @_;
148 10 50       15 croak 'can\'t quote undefined value' if !defined $s;
149 10 100       28 if ($s =~ / \s | ' | \A\z /xms) {
150 2         4 $s =~ s/'/''/xmsg;
151 2         3 $s = "'$s'";
152             }
153 10         30 return $s;
154             }
155              
156             sub _unquote {
157 12     12   62 my ($s) = @_;
158 12 100       21 if ($s =~ s/\A'(.*)'\z/$1/xms) {
159 1         3 $s =~ s/''/'/xmsg;
160             }
161 12         43 return $s;
162             }
163              
164             sub quote_list :Export {
165 4     4 0 8 return join q{ }, map {_quote($_)} @_;
  10         16  
166 3     3   999 }
  3         5  
  3         20  
167              
168             sub unquote_list :Export {
169 22     22 0 45 my ($s) = @_;
170 22 100       42 return if !defined $s;
171 3         5 my @w;
172 3         25 while ($s =~ /\G ( [^'\s]+ | '[^']*(?:''[^']*)*' ) (?:\s+|\z)/xmsgc) {
173 12         19 my $w = $1;
174 12         17 push @w, _unquote($w);
175             }
176 3 50       11 return if $s !~ /\G\z/xmsg;
177 3         6 return \@w;
178 3     3   806 }
  3         20  
  3         12  
179              
180             sub unquote_hash :Export {
181 22     22 0 36 my $w = unquote_list(@_);
182 22 100 66     75 return $w && $#{$w} % 2 ? { @{$w} } : undef;
  3         13  
183 3     3   560 }
  3         5  
  3         9  
184              
185              
186             1; # Magic true value required at end of module
187             __END__