/[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.5 - (show annotations) (download)
Sun Nov 9 14:06:23 2008 UTC (16 years ago) by wakaba
Branch: MAIN
Changes since 1.4: +8 -3 lines
++ manakai/lib/Message/CGI/ChangeLog	29 Oct 2008 05:42:58 -0000
2008-10-29  Wakaba  <wakaba@suika.fam.cx>

	* HTTP.pm (remote_user): New method.

++ manakai/lib/Message/DOM/ChangeLog	9 Nov 2008 14:06:17 -0000
2008-11-09  Wakaba  <wakaba@suika.fam.cx>

	* Element.pm (inner_html): Setter for HTML element nodes
	implemented.

1 =head1 NAME
2
3 Message::CGI::HTTP - An Object-Oriented HTTP CGI Interface
4
5 =head1 DESCRIPTION
6
7 The C<Message::CGI::HTTP> module provides an object-oriented
8 interface for inputs and outputs as defined by CGI specification.
9
10 This module is part of manakai.
11
12 =cut
13
14 package Message::CGI::HTTP;
15 use strict;
16 our $VERSION = do{my @r=(q$Revision: 1.4 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
17 push our @ISA, 'Message::IF::CGIRequest', 'Message::IF::HTTPCGIRequest';
18
19 =head1 METHODS
20
21 =over 4
22
23 =item I<$cgi> = Message::CGI::HTTP->new;
24
25 Creates and returns a new instance of HTTP CGI interface object.
26
27 =cut
28
29 sub new ($;%) {
30 my $self = bless {
31 decoder => {
32 '#default' => sub {$_[1]},
33 },
34 }, shift;
35 my %opt = @_;
36 $self->{-in_handle} = *main::STDIN;
37 $self;
38 } # new
39
40 =item I<$value> = I<$cgi>->get_meta_variable (I<$name>)
41
42 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
52 This method might return C<undef> when the meta-variable
53 is not defined or is defined but its value is C<undef>.
54
55 =cut
56
57 sub get_meta_variable ($$) {
58 return $main::ENV{ $_[1] };
59 } # get_meta_variable
60
61 =item I<$list> = I<$cgi>->meta_variable_names;
62
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 This method returns a C<Message::DOM::DOMStringList>.
75
76 =cut
77
78 sub meta_variable_names ($) {
79 require Message::DOM::DOMStringList;
80 bless [keys %main::ENV], 'Message::DOM::DOMStringList::StaticList';
81 } # meta_variable_names
82
83 =item I<$value> = C<$cgi>->get_parameter ($name);
84
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 =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
109 Returnes a list of parameter names provided.
110
111 This method returns a C<Message::DOM::DOMStringList>.
112
113 =cut
114
115 sub parameter_names ($) {
116 my $self = shift;
117 $self->__get_parameter unless $self->{param};
118
119 require Message::DOM::DOMStringList;
120 return bless [keys %{$self->{param}}],
121 'Message::DOM::DOMStringList::StaticList';
122 } # parameter_names
123
124 sub __get_parameter ($) {
125 my $self = shift;
126 my @src;
127
128 ## Query-string of Request-URI
129 my $qs = $self->get_meta_variable ('QUERY_STRING');
130 push @src, $qs if (index ($qs, '=') > -1);
131
132 ## Entity-body
133 if ($self->get_meta_variable ('REQUEST_METHOD') eq 'POST') {
134 my $mt = $self->get_meta_variable ('CONTENT_TYPE');
135 ## TODO: Uppercase
136 if ($mt =~ m<^application/(?:x-www|sgml)-form-urlencoded\b>) {
137 push @src, $self->entity_body;
138 }
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 } # __get_parameter
164
165 =item I<$body> = I<$cgi>->entity_body;
166
167 Returns entity-body content if any.
168
169 =cut
170
171 sub entity_body ($) {
172 my $self = shift;
173 $self->__get_entity_body unless defined $self->{body};
174
175 return $self->{body};
176 } # entity_body
177
178 sub __get_entity_body ($) {
179 my $self = shift;
180 binmode $self->{-in_handle};
181 read $self->{-in_handle}, $self->{body},
182 $self->get_meta_variable ('CONTENT_LENGTH');
183 } # __get_entity_body
184 ## TODO: Entity too large
185
186 =item I<$uri> = I<$cgi>->request_uri;
187
188 Returns Request-URI as a C<Message::URI::URIReference> object.
189
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 require Message::URI::URIReference;
200 my $uri = $opt{no_path_info} ? undef
201 : $self->get_meta_variable ('REQUEST_URI'); # non-standard
202 if ($uri) {
203 $uri =~ s/\#[^#]*$//; ## Fragment identifier not allowed here
204 $uri =~ s/\?[^?]*$// if $opt{no_query};
205 if ($uri =~ /^[0-9A-Za-z.%+-]+:/) { ## REQUEST_URI is an absolute URI
206 return Message::DOM::DOMImplementation->create_uri_reference ($uri);
207 }
208 } else { ## REQUEST_URI is not provided
209 my $pi = $opt{no_path_info} ? q<>
210 : $self->get_meta_variable ('PATH_INFO');
211 $uri = $self->__uri_encode ($self->get_meta_variable ('SCRIPT_NAME').$pi,
212 qr([^0-9A-Za-z_.!~*'();/:\@&=\$,-]));
213 my $qs = $self->get_meta_variable ('QUERY_STRING');
214 $uri .= '?' . $qs if not $opt{no_query} and defined $qs;
215 }
216
217 ## REQUEST_URI is a relative URI or
218 ## REQUEST_URI is not provided
219 my $scheme = 'http';
220 my $port = ':' . $self->get_meta_variable ('SERVER_PORT');
221 ## TODO: HTTPS=off
222 if ( $self->get_meta_variable ('HTTPS')
223 || $self->get_meta_variable ('CERT_SUBJECT')
224 || $self->get_meta_variable ('SSL_VERSION')) {
225 $scheme = 'https';
226 $port = '' if $port eq ':443';
227 } else {
228 $port = '' if $port eq ':80';
229 }
230
231 my $host_and_port = $self->get_meta_variable ('HTTP_HOST');
232 if ($host_and_port) {
233 $uri = $scheme . '://'
234 . $self->__uri_encode ($host_and_port, qr/[^0-9A-Za-z.:-]/)
235 . $uri; ## ISSUE: Should we allow "[" / "]" for IPv6 here?
236 } else {
237 $uri = $scheme . '://'
238 . $self->__uri_encode ($self->get_meta_variable ('SERVER_NAME'),
239 qr/[^0-9A-Za-z.-]/)
240 . $port . $uri;
241 }
242 return Message::DOM::DOMImplementation->create_uri_reference ($uri);
243 } # request_uri
244
245 sub __uri_encode ($$;$) {
246 my ($self, $s, $char) = @_;
247 $char ||= qr([^0-9A-Za-z_.!~*'();/?:\@&=+\$,-]);
248 require Encode;
249 $s = Encode::decode ('utf8', $s);
250 $s =~ s/($char)/sprintf '%%%02X', ord $1/ge;
251 return $s;
252 } # __uri_encode
253
254 =item I<$value> = I<$cgi>->path_info ([I<$new_value>]);
255
256 =item I<$value> = I<$cgi>->remote_user ([I<$new_value>]);
257
258 These methods reflect meta-variables with the same name (in
259 uppercase).
260
261 =cut
262
263 for (
264 [path_info => 'PATH_INFO'],
265 [query_string => 'QUERY_STRING'],
266 [remote_user => 'REMOTE_USER'],
267 [request_method => 'REQUEST_METHOD'],
268 [script_name => 'SCRIPT_NAME'],
269 ) {
270 eval qq{
271 sub $_->[0] (\$;\$) {
272 if (\@_ > 1) {
273 if (defined \$_[1]) {
274 \$main::ENV{'$_->[1]'} = ''.\$_[1];
275 } else {
276 delete \$main::ENV{'$_->[1]'};
277 }
278 }
279 return \$main::ENV{'$_->[1]'};
280 }
281 };
282 }
283
284 package Message::IF::CGIRequest;
285 package Message::IF::HTTPCGIRequest;
286
287 =back
288
289 =head1 TODO
290
291 =over 4
292
293 =item multipart/form-data support
294
295 =back
296
297 =head1 SEE ALSO
298
299 A draft specification for DOM CGI Module
300 <http://suika.fam.cx/gate/2005/sw/manakai/%E3%83%A1%E3%83%A2/2005-07-04>
301 (This module does not implement the interface defined in this
302 specification, however.)
303
304 =head1 AUTHOR
305
306 Wakaba <w@suika.fam.cx>
307
308 This module was originally developed as part of SuikaWiki.
309
310 =head1 LICENSE
311
312 Copyright 2003, 2007 Wakaba <w@suika.fam.cx>
313
314 This program is free software; you can redistribute it and/or
315 modify it under the same terms as Perl itself.
316
317 =cut
318
319 1;
320 # $Date: 2007/08/22 10:59:43 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24