]> mj.ucw.cz Git - libucw.git/blobdiff - lib/perl/CGI.pm
CGI: Added "multiline" flag, which allows newline in parameter values.
[libucw.git] / lib / perl / CGI.pm
index aeb6c50504a52a4c8bdda50fa4e11cd1d087ebd5..55e76e1c7fb4b56a79ad20148a80b10b47cb4f11 100644 (file)
@@ -1,12 +1,12 @@
 #      Poor Man's CGI Module for Perl
 #
-#      (c) 2002 Martin Mares <mj@ucw.cz>
+#      (c) 2002--2007 Martin Mares <mj@ucw.cz>
 #      Slightly modified by Tomas Valla <tom@ucw.cz>
 #
 #      This software may be freely distributed and used according to the terms
 #      of the GNU Lesser General Public License.
 
-package Sherlock::CGI;
+package UCW::CGI;
 
 use strict;
 use warnings;
@@ -17,17 +17,26 @@ BEGIN {
        our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
        $VERSION = 1.0;
        @ISA = qw(Exporter);
-       @EXPORT = qw(&html_escape &url_escape &self_ref &self_form);
+       @EXPORT = qw(&html_escape &url_escape &url_param_escape &self_ref &self_form);
        @EXPORT_OK = qw();
        %EXPORT_TAGS = ();
 }
 
+### Escaping ###
+
 sub url_escape($) {
        my $x = shift @_;
        $x =~ s/([^-\$_.!*'(),0-9A-Za-z\x80-\xff])/"%".unpack('H2',$1)/ge;
        return $x;
 }
 
+sub url_param_escape($) {
+       my $x = shift @_;
+       $x = url_escape($x);
+       $x =~ s/%20/+/g;
+       return $x;
+}
+
 sub html_escape($) {
        my $x = shift @_;
        $x =~ s/&/&amp;/g;
@@ -37,6 +46,41 @@ sub html_escape($) {
        return $x;
 }
 
+### Analysing RFC 822 Style Headers ###
+
+sub rfc822_prepare($) {
+       my $x = shift @_;
+       # Convert all %'s and backslash escapes to %xx escapes
+       $x =~ s/%/%25/g;
+       $x =~ s/\\(.)/"%".unpack("H2",$1)/ge;
+       # Remove all comments, beware, they can be nested (unterminated comments are closed at EOL automatically)
+       while ($x =~ s/^(("[^"]*"|[^"(])*(\([^)]*)*)(\([^()]*(\)|$))/$1 /) { }
+       # Remove quotes and escape dangerous characters inside (again closing at the end automatically)
+       $x =~ s{"([^"]*)("|$)}{my $z=$1; $z =~ s/([^0-9a-zA-Z%_-])/"%".unpack("H2",$1)/ge; $z;}ge;
+       # All control characters are properly escaped, tokens are clearly visible.
+       # Finally remove all unnecessary spaces.
+       $x =~ s/\s+/ /g;
+       $x =~ s/(^ | $)//g;
+       $x =~ s{\s*([()<>@,;:\\"/\[\]?=])\s*}{$1}g;
+       return $x;
+}
+
+sub rfc822_deescape($) {
+       my $x = shift @_;
+       $x =~ s/%(..)/pack("H2",$1)/ge;
+       return $x;
+}
+
+### Reading of HTTP headers ###
+
+sub http_get($) {
+       my $h = shift @_;
+       $h =~ tr/a-z-/A-Z_/;
+       return $ENV{"HTTP_$h"} || $ENV{"$h"};
+}
+
+### Parsing of Arguments ###
+
 our $arg_table;
 
 sub parse_arg_string($) {
@@ -47,14 +91,16 @@ sub parse_arg_string($) {
                my $arg = $arg_table->{$1} or next;
                $_ = $2;
                s/\+/ /g;
-               s/%(..)/pack("c",hex $1)/eg;
-               s/(\r|\n|\t)/ /g;
+               s/%(..)/pack("H2",$1)/eg;
+               s/\r\n/\n/g;
+               s/\r/\n/g;
+               $arg->{'multiline'} || s/(\n|\t)/ /g;
                s/^\s+//;
                s/\s+$//;
                if (my $rx = $arg->{'check'}) {
                        if (!/^$rx$/) { $_ = $arg->{'default'}; }
                }
-               
+
                my $r = ref($arg->{'var'});
                if ($r eq 'SCALAR') {
                        ${$arg->{'var'}} = $_;
@@ -93,12 +139,15 @@ sub parse_args($) {
        }
 }
 
+### Generating Self-ref URL's ###
+
 sub make_out_args($) {
        my ($overrides) = @_;
        my $out = {};
        foreach my $name (keys %$arg_table) {
                my $arg = $arg_table->{$name};
-               defined $arg->{'pass'} && !$arg->{'pass'} && !exists $overrides->{$name} && next;
+               defined($arg->{'var'}) || next;
+               defined($arg->{'pass'}) && !$arg->{'pass'} && !exists $overrides->{$name} && next;
                my $value;
                if (!defined($value = $overrides->{$name})) {
                        if (exists $overrides->{$name}) {
@@ -117,7 +166,7 @@ sub make_out_args($) {
 sub self_ref(@) {
        my %h = @_;
        my $out = make_out_args(\%h);
-       return "?" . join(':', map { "$_=" . url_escape($out->{$_}) } sort keys %$out);
+       return "?" . join(':', map { "$_=" . url_param_escape($out->{$_}) } sort keys %$out);
 }
 
 sub self_form(@) {
@@ -126,4 +175,42 @@ sub self_form(@) {
        return join('', map { "<input type=hidden name=$_ value='" . html_escape($out->{$_}) . "'>\n" } sort keys %$out);
 }
 
+### Cookies
+
+sub cookie_esc($) {
+       my $x = shift @_;
+       if ($x !~ /^[a-zA-Z0-9%]+$/) {
+               $x =~ s/([\\\"])/\\$1/g;
+               $x = "\"$x\"";
+       }
+       return $x;
+}
+
+sub set_cookie($$@) {
+       my $key = shift @_;
+       my $value = shift @_;
+       my %other = @_;
+       $other{'version'} = 1 unless defined $other{'version'};
+       print "Set-Cookie: $key=", cookie_esc($value);
+       foreach my $k (keys %other) {
+               print ";$k=", cookie_esc($other{$k});
+       }
+       print "\n";
+}
+
+sub parse_cookies() {
+       my $h = http_get("Cookie") or return ();
+       my @cook = ();
+       while (my ($padding,$name,$val,$xx,$rest) = ($h =~ /\s*([,;]\s*)*([^ =]+)=([^ =,;\"]*|\"([^\"\\]|\\.)*\")(\s.*|;.*|$)/)) {
+               if ($val =~ /^\"/) {
+                       $val =~ s/^\"//;
+                       $val =~ s/\"$//;
+                       $val =~ s/\\(.)/$1/g;
+               }
+               push @cook, $name, $val;
+               $h = $rest;
+       }
+       return @cook;
+}
+
 1;  # OK