/[suikacvs]/messaging/manakai/lib/Message/CGI/HTTP.pm
Suika

Contents of /messaging/manakai/lib/Message/CGI/HTTP.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Mon Nov 10 05:30:59 2008 UTC (16 years ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +3 -2 lines
++ manakai/lib/Message/CGI/ChangeLog	10 Nov 2008 05:30:33 -0000
2008-11-10  Wakaba  <wakaba@suika.fam.cx>

	* HTTP.pm (request_uri): Percent-escape non-ASCII octets in
	REQUEST_URI to avoid they become unclear whether they are bytes or
	characters in later processing.

++ manakai/lib/Message/URI/ChangeLog	10 Nov 2008 05:30:51 -0000
2008-11-10  Wakaba  <wakaba@suika.fam.cx>

	* URIReference.pm (is_relative_iri_reference_3987): Escapes in
	$ucschar was not expanded.

1 wakaba 1.1 =head1 NAME
2    
3 wakaba 1.2 Message::CGI::HTTP - An Object-Oriented HTTP CGI Interface
4 wakaba 1.1
5     =head1 DESCRIPTION
6    
7 wakaba 1.2 The C<Message::CGI::HTTP> module provides an object-oriented
8     interface for inputs and outputs as defined by CGI specification.
9 wakaba 1.1
10 wakaba 1.2 This module is part of manakai.
11 wakaba 1.1
12     =cut
13    
14 wakaba 1.2 package Message::CGI::HTTP;
15 wakaba 1.1 use strict;
16 wakaba 1.6 our $VERSION = do{my @r=(q$Revision: 1.5 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
17 wakaba 1.4 push our @ISA, 'Message::IF::CGIRequest', 'Message::IF::HTTPCGIRequest';
18 wakaba 1.1
19     =head1 METHODS
20    
21     =over 4
22    
23 wakaba 1.2 =item I<$cgi> = Message::CGI::HTTP->new;
24 wakaba 1.1
25 wakaba 1.2 Creates and returns a new instance of HTTP CGI interface object.
26 wakaba 1.1
27     =cut
28    
29     sub new ($;%) {
30     my $self = bless {
31     decoder => {
32     '#default' => sub {$_[1]},
33     },
34     }, shift;
35     my %opt = @_;
36 wakaba 1.2 $self->{-in_handle} = *main::STDIN;
37 wakaba 1.1 $self;
38 wakaba 1.2 } # new
39    
40     =item I<$value> = I<$cgi>->get_meta_variable (I<$name>)
41 wakaba 1.1
42 wakaba 1.2 Returns the value of the meta-variable I<$name>. The name
43     specified by the I<$name> SHOULD be a meta-variable name
44     defined by a CGI specification, e.g. C<CONTENT_TYPE> or
45     C<HTTP_USER_AGENT>. Otherwise, the result is implementation
46     dependent. In an environment where meta-variables are supplied
47     as envirnoment variables, specifying an environment variable
48     that is not a meta-variable, such as C<PATH>, results in the
49     value of that environment variable. However, CGI scripts
50     SHOULD NOT depend on such behavior.
51 wakaba 1.1
52 wakaba 1.2 This method might return C<undef> when the meta-variable
53     is not defined or is defined but its value is C<undef>.
54 wakaba 1.1
55     =cut
56    
57 wakaba 1.2 sub get_meta_variable ($$) {
58     return $main::ENV{ $_[1] };
59     } # get_meta_variable
60 wakaba 1.1
61 wakaba 1.2 =item I<$list> = I<$cgi>->meta_variable_names;
62 wakaba 1.1
63     Returns list of meta variables. Note that this list might contain
64     other environmental variables than CGI meta variables, since
65     they cannot distinglish unless we know what is CGI meta variable
66     and what is not. Unfortunately, there is no complete list of CGI
67     meta variables, whilst list of standarized meta variables is available.
68    
69     NOTE: Some application might use an environmental variable named
70     'HTTP_HOME', which might make some confusion with CGI meta variable
71     for HTTP 'Home:' header field. Fortunately, such name of HTTP
72     header field is not intoroduced as far as I know.
73    
74 wakaba 1.3 This method returns a C<Message::DOM::DOMStringList>.
75 wakaba 1.2
76 wakaba 1.1 =cut
77    
78 wakaba 1.2 sub meta_variable_names ($) {
79     require Message::DOM::DOMStringList;
80     bless [keys %main::ENV], 'Message::DOM::DOMStringList::StaticList';
81     } # meta_variable_names
82 wakaba 1.1
83 wakaba 1.2 =item I<$value> = C<$cgi>->get_parameter ($name);
84 wakaba 1.1
85     Returns parameter value if any.
86     Parameter value is set by query-string of Request-URI
87     and/or entity-body value.
88    
89     When multiple values with same parameter name is specified,
90     the first one is returned in scalar context or
91     an array reference of all values is returned in array context.
92     (Note that query-string is "earlier" than entity-body.)
93    
94 wakaba 1.2 =cut
95    
96     sub get_parameter ($$) {
97     my ($self, $name) = @_;
98     $self->__get_parameter unless $self->{param};
99    
100     if (wantarray) {
101     return @{$self->{param}->{$name}||[]};
102     } else {
103     return ${$self->{param}->{$name}||[]}[0];
104     }
105     } # get_parameter
106    
107     =item I<$keys> = I<$cgi>->parameter_names;
108 wakaba 1.1
109     Returnes a list of parameter names provided.
110    
111 wakaba 1.3 This method returns a C<Message::DOM::DOMStringList>.
112 wakaba 1.2
113 wakaba 1.1 =cut
114    
115     sub parameter_names ($) {
116     my $self = shift;
117     $self->__get_parameter unless $self->{param};
118 wakaba 1.2
119     require Message::DOM::DOMStringList;
120     return bless [keys %{$self->{param}}],
121     'Message::DOM::DOMStringList::StaticList';
122     } # parameter_names
123 wakaba 1.1
124     sub __get_parameter ($) {
125     my $self = shift;
126     my @src;
127    
128     ## Query-string of Request-URI
129 wakaba 1.3 my $qs = $self->get_meta_variable ('QUERY_STRING');
130 wakaba 1.1 push @src, $qs if (index ($qs, '=') > -1);
131    
132     ## Entity-body
133 wakaba 1.3 if ($self->get_meta_variable ('REQUEST_METHOD') eq 'POST') {
134     my $mt = $self->get_meta_variable ('CONTENT_TYPE');
135 wakaba 1.5 ## TODO: Uppercase
136 wakaba 1.1 if ($mt =~ m<^application/(?:x-www|sgml)-form-urlencoded\b>) {
137 wakaba 1.3 push @src, $self->entity_body;
138 wakaba 1.1 }
139     ## TODO: support non-standard "charset" parameter
140     }
141    
142     my %temp_params;
143     for my $src (@src) {
144     for (split /[;&]/, $src) {
145     my ($name, $val) = split '=', $_, 2;
146     for ($name, $val) {
147     tr/+/ /;
148     s/%([0-9A-Fa-f][0-9A-Fa-f])/pack 'C', hex $1/ge;
149     }
150     $temp_params{$name} ||= [];
151     push @{$temp_params{$name}}, $val;
152     }
153     }
154     for (keys %temp_params) {
155     my $name = &{$self->{decoder}->{'#name'}
156     ||$self->{decoder}->{'#default'}} ($self, $_, \%temp_params);
157     for (@{$temp_params{$name}}) {
158     push @{$self->{param}->{$name}},
159     &{$self->{decoder}->{$name}
160     ||$self->{decoder}->{'#default'}} ($self, $_, \%temp_params);
161     }
162     }
163 wakaba 1.3 } # __get_parameter
164 wakaba 1.1
165 wakaba 1.2 =item I<$body> = I<$cgi>->entity_body;
166 wakaba 1.1
167     Returns entity-body content if any.
168    
169     =cut
170    
171 wakaba 1.2 sub entity_body ($) {
172 wakaba 1.1 my $self = shift;
173     $self->__get_entity_body unless defined $self->{body};
174    
175 wakaba 1.2 return $self->{body};
176     } # entity_body
177 wakaba 1.1
178     sub __get_entity_body ($) {
179     my $self = shift;
180     binmode $self->{-in_handle};
181     read $self->{-in_handle}, $self->{body},
182 wakaba 1.3 $self->get_meta_variable ('CONTENT_LENGTH');
183 wakaba 1.2 } # __get_entity_body
184 wakaba 1.1 ## TODO: Entity too large
185    
186 wakaba 1.2 =item I<$uri> = I<$cgi>->request_uri;
187 wakaba 1.1
188 wakaba 1.3 Returns Request-URI as a C<Message::URI::URIReference> object.
189 wakaba 1.1
190     Note that stringified value of returned value might not be same as the
191     URI specified as the Request-URI of HTTP request or (possibly pseudo-)
192     URI entered by the user, since no standarized way to get it is
193     defined by HTTP and CGI/1.1 specifications.
194    
195     =cut
196    
197     sub request_uri ($;%) {
198     my ($self, %opt) = @_;
199 wakaba 1.2 require Message::URI::URIReference;
200 wakaba 1.1 my $uri = $opt{no_path_info} ? undef
201 wakaba 1.3 : $self->get_meta_variable ('REQUEST_URI'); # non-standard
202 wakaba 1.1 if ($uri) {
203     $uri =~ s/\#[^#]*$//; ## Fragment identifier not allowed here
204     $uri =~ s/\?[^?]*$// if $opt{no_query};
205 wakaba 1.6 $uri = $self->__uri_encode ($uri, qr([^\x00-\x7F]));
206 wakaba 1.1 if ($uri =~ /^[0-9A-Za-z.%+-]+:/) { ## REQUEST_URI is an absolute URI
207 wakaba 1.2 return Message::DOM::DOMImplementation->create_uri_reference ($uri);
208 wakaba 1.1 }
209     } else { ## REQUEST_URI is not provided
210     my $pi = $opt{no_path_info} ? q<>
211 wakaba 1.3 : $self->get_meta_variable ('PATH_INFO');
212     $uri = $self->__uri_encode ($self->get_meta_variable ('SCRIPT_NAME').$pi,
213 wakaba 1.1 qr([^0-9A-Za-z_.!~*'();/:\@&=\$,-]));
214 wakaba 1.3 my $qs = $self->get_meta_variable ('QUERY_STRING');
215 wakaba 1.1 $uri .= '?' . $qs if not $opt{no_query} and defined $qs;
216     }
217    
218     ## REQUEST_URI is a relative URI or
219     ## REQUEST_URI is not provided
220     my $scheme = 'http';
221 wakaba 1.3 my $port = ':' . $self->get_meta_variable ('SERVER_PORT');
222 wakaba 1.1 ## TODO: HTTPS=off
223 wakaba 1.3 if ( $self->get_meta_variable ('HTTPS')
224     || $self->get_meta_variable ('CERT_SUBJECT')
225     || $self->get_meta_variable ('SSL_VERSION')) {
226 wakaba 1.1 $scheme = 'https';
227     $port = '' if $port eq ':443';
228     } else {
229     $port = '' if $port eq ':80';
230     }
231    
232 wakaba 1.3 my $host_and_port = $self->get_meta_variable ('HTTP_HOST');
233 wakaba 1.1 if ($host_and_port) {
234     $uri = $scheme . '://'
235     . $self->__uri_encode ($host_and_port, qr/[^0-9A-Za-z.:-]/)
236     . $uri; ## ISSUE: Should we allow "[" / "]" for IPv6 here?
237     } else {
238     $uri = $scheme . '://'
239 wakaba 1.3 . $self->__uri_encode ($self->get_meta_variable ('SERVER_NAME'),
240 wakaba 1.1 qr/[^0-9A-Za-z.-]/)
241     . $port . $uri;
242     }
243 wakaba 1.2 return Message::DOM::DOMImplementation->create_uri_reference ($uri);
244     } # request_uri
245 wakaba 1.1
246     sub __uri_encode ($$;$) {
247     my ($self, $s, $char) = @_;
248     $char ||= qr([^0-9A-Za-z_.!~*'();/?:\@&=+\$,-]);
249     require Encode;
250     $s = Encode::decode ('utf8', $s);
251     $s =~ s/($char)/sprintf '%%%02X', ord $1/ge;
252 wakaba 1.2 return $s;
253     } # __uri_encode
254 wakaba 1.1
255 wakaba 1.4 =item I<$value> = I<$cgi>->path_info ([I<$new_value>]);
256    
257 wakaba 1.5 =item I<$value> = I<$cgi>->remote_user ([I<$new_value>]);
258    
259     These methods reflect meta-variables with the same name (in
260     uppercase).
261 wakaba 1.4
262     =cut
263    
264     for (
265     [path_info => 'PATH_INFO'],
266     [query_string => 'QUERY_STRING'],
267 wakaba 1.5 [remote_user => 'REMOTE_USER'],
268 wakaba 1.4 [request_method => 'REQUEST_METHOD'],
269     [script_name => 'SCRIPT_NAME'],
270     ) {
271     eval qq{
272     sub $_->[0] (\$;\$) {
273     if (\@_ > 1) {
274     if (defined \$_[1]) {
275     \$main::ENV{'$_->[1]'} = ''.\$_[1];
276     } else {
277     delete \$main::ENV{'$_->[1]'};
278     }
279     }
280     return \$main::ENV{'$_->[1]'};
281     }
282     };
283     }
284    
285 wakaba 1.2 package Message::IF::CGIRequest;
286 wakaba 1.4 package Message::IF::HTTPCGIRequest;
287 wakaba 1.1
288 wakaba 1.2 =back
289 wakaba 1.1
290 wakaba 1.2 =head1 TODO
291 wakaba 1.1
292 wakaba 1.2 =over 4
293 wakaba 1.1
294 wakaba 1.2 =item multipart/form-data support
295 wakaba 1.1
296 wakaba 1.2 =back
297 wakaba 1.1
298 wakaba 1.2 =head1 SEE ALSO
299 wakaba 1.1
300 wakaba 1.2 A draft specification for DOM CGI Module
301     <http://suika.fam.cx/gate/2005/sw/manakai/%E3%83%A1%E3%83%A2/2005-07-04>
302     (This module does not implement the interface defined in this
303     specification, however.)
304 wakaba 1.1
305 wakaba 1.2 =head1 AUTHOR
306 wakaba 1.1
307 wakaba 1.2 Wakaba <w@suika.fam.cx>
308 wakaba 1.1
309 wakaba 1.3 This module was originally developed as part of SuikaWiki.
310    
311 wakaba 1.1 =head1 LICENSE
312    
313 wakaba 1.2 Copyright 2003, 2007 Wakaba <w@suika.fam.cx>
314 wakaba 1.1
315     This program is free software; you can redistribute it and/or
316     modify it under the same terms as Perl itself.
317    
318     =cut
319    
320 wakaba 1.2 1;
321 wakaba 1.6 # $Date: 2008/11/09 14:06:23 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24