1 # Poor Man's CGI Module for Perl
3 # (c) 2002--2007 Martin Mares <mj@ucw.cz>
4 # Slightly modified by Tomas Valla <tom@ucw.cz>
6 # This software may be freely distributed and used according to the terms
7 # of the GNU Lesser General Public License.
15 # The somewhat hairy Perl export mechanism
17 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
20 @EXPORT = qw(&html_escape &url_escape &url_param_escape &self_ref &self_form);
29 $x =~ s/([^-\$_.!*'(),0-9A-Za-z\x80-\xff])/"%".unpack('H2',$1)/ge;
33 sub url_param_escape($) {
49 ### Analysing RFC 822 Style Headers ###
51 sub rfc822_prepare($) {
53 # Convert all %'s and backslash escapes to %xx escapes
55 $x =~ s/\\(.)/"%".unpack("H2",$1)/ge;
56 # Remove all comments, beware, they can be nested (unterminated comments are closed at EOL automatically)
57 while ($x =~ s/^(("[^"]*"|[^"(])*(\([^)]*)*)(\([^()]*(\)|$))/$1 /) { }
58 # Remove quotes and escape dangerous characters inside (again closing at the end automatically)
59 $x =~ s{"([^"]*)("|$)}{my $z=$1; $z =~ s/([^0-9a-zA-Z%_-])/"%".unpack("H2",$1)/ge; $z;}ge;
60 # All control characters are properly escaped, tokens are clearly visible.
61 # Finally remove all unnecessary spaces.
64 $x =~ s{\s*([()<>@,;:\\"/\[\]?=])\s*}{$1}g;
68 sub rfc822_deescape($) {
70 $x =~ s/%(..)/pack("H2",$1)/ge;
74 ### Reading of HTTP headers ###
79 return $ENV{"HTTP_$h"} || $ENV{"$h"};
82 ### Parsing of Arguments ###
86 sub parse_arg_string($) {
89 foreach $_ (split /[&:]/,$s) {
90 (/^([^=]+)=(.*)$/) or next;
91 my $arg = $arg_table->{$1} or next;
94 s/%(..)/pack("H2",$1)/eg;
97 $arg->{'multiline'} || s/(\n|\t)/ /g;
100 if (my $rx = $arg->{'check'}) {
101 if (!/^$rx$/) { $_ = $arg->{'default'}; }
104 my $r = ref($arg->{'var'});
105 if ($r eq 'SCALAR') {
106 ${$arg->{'var'}} = $_;
107 } elsif ($r eq 'ARRAY') {
108 push @{$arg->{'var'}}, $_;
114 $arg_table = shift @_;
115 foreach my $a (values %$arg_table) {
116 my $r = ref($a->{'var'});
117 defined($a->{'default'}) or $a->{'default'}="";
118 if ($r eq 'SCALAR') {
119 ${$a->{'var'}} = $a->{'default'};
120 } elsif ($r eq 'ARRAY') {
124 defined $ENV{"GATEWAY_INTERFACE"} or die "Not called as a CGI script";
125 my $method = $ENV{"REQUEST_METHOD"};
126 if ($method eq "GET") {
127 parse_arg_string($ENV{"QUERY_STRING"});
128 } elsif ($method eq "POST") {
129 if ($ENV{"CONTENT_TYPE"} =~ /^application\/x-www-form-urlencoded\b/i) {
132 parse_arg_string($_);
135 return "Unknown content type for POST data";
138 return "Unknown request method";
142 ### Generating Self-ref URL's ###
144 sub make_out_args($) {
145 my ($overrides) = @_;
147 foreach my $name (keys %$arg_table) {
148 my $arg = $arg_table->{$name};
149 defined($arg->{'var'}) || next;
150 defined($arg->{'pass'}) && !$arg->{'pass'} && !exists $overrides->{$name} && next;
152 if (!defined($value = $overrides->{$name})) {
153 if (exists $overrides->{$name}) {
154 $value = $arg->{'default'};
156 $value = ${$arg->{'var'}};
159 if ($value ne $arg->{'default'}) {
160 $out->{$name} = $value;
168 my $out = make_out_args(\%h);
169 return "?" . join(':', map { "$_=" . url_param_escape($out->{$_}) } sort keys %$out);
174 my $out = make_out_args(\%h);
175 return join('', map { "<input type=hidden name=$_ value='" . html_escape($out->{$_}) . "'>\n" } sort keys %$out);
182 if ($x !~ /^[a-zA-Z0-9%]+$/) {
183 $x =~ s/([\\\"])/\\$1/g;
189 sub set_cookie($$@) {
191 my $value = shift @_;
193 $other{'version'} = 1 unless defined $other{'version'};
194 print "Set-Cookie: $key=", cookie_esc($value);
195 foreach my $k (keys %other) {
196 print ";$k=", cookie_esc($other{$k});
201 sub parse_cookies() {
202 my $h = http_get("Cookie") or return ();
204 while (my ($padding,$name,$val,$xx,$rest) = ($h =~ /\s*([,;]\s*)*([^ =]+)=([^ =,;\"]*|\"([^\"\\]|\\.)*\")(\s.*|;.*|$)/)) {
208 $val =~ s/\\(.)/$1/g;
210 push @cook, $name, $val;