File Coverage

blib/lib/Net/HTTPServer/Request.pm
Criterion Covered Total %
statement 103 127 81.1
branch 27 34 79.4
condition 2 6 33.3
subroutine 18 23 78.2
pod 10 12 83.3
total 160 202 79.2


line stmt bran cond sub pod time code
1             ##############################################################################
2             #
3             # This library is free software; you can redistribute it and/or
4             # modify it under the terms of the GNU Library General Public
5             # License as published by the Free Software Foundation; either
6             # version 2 of the License, or (at your option) any later version.
7             #
8             # This library is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11             # Library General Public License for more details.
12             #
13             # You should have received a copy of the GNU Library General Public
14             # License along with this library; if not, write to the
15             # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16             # Boston, MA 02111-1307, USA.
17             #
18             # Copyright (C) 2003-2005 Ryan Eatmon
19             #
20             ##############################################################################
21             package Net::HTTPServer::Request;
22              
23             =head1 NAME
24              
25             Net::HTTPServer::Request
26              
27             =head1 SYNOPSIS
28              
29             Net::HTTPServer::Request handles the parsing of a request.
30            
31             =head1 DESCRIPTION
32              
33             Net::HTTPServer::Request takes a full request, parses it, and then provides
34             a nice OOP interface to pulling out the information you want from a request.
35              
36             =head1 METHODS
37              
38             =head2 Cookie([cookie])
39              
40             Returns a hash reference of cookie/value pairs. If you specify a cookie,
41             then it returns the value for that cookie, or undef if it does not exist.
42              
43             =head2 Env([var])
44              
45             Returns a hash reference of variable/value pairs. If you specify a
46             variable, then it returns the value for that variable, or undef if it does
47             not exist.
48              
49             =head2 Header([header])
50              
51             Returns a hash reference of header/value pairs. If you specify a header,
52             then it returns the value for that header, or undef if it does not exist.
53              
54             =head2 Method()
55              
56             Returns the method of the request (GET,POST,etc...)
57              
58             =head2 Path()
59              
60             Returns the path portion of the URL. Does not include any query
61             strings.
62              
63             =head2 Procotol()
64              
65             Returns the name and revision that the request came in with.
66              
67             =head2 Query()
68              
69             Returns the query portion of the URL (if any). You can combine the Path
70             and the Query with a ? to get the real URL that the client requested.
71              
72             =head2 Request()
73              
74             Returns the entire request as a string.
75              
76             =head2 Response()
77              
78             Returns a Net::HTTPServer::Response object with various bits prefilled
79             in. If you have created session via the Session() method, then the
80             session will already be registered with the response.
81              
82             =head2 Session()
83              
84             Create a new Net::HTTPServer::Session object. If the cookie value is set,
85             then the previous state values are loaded, otherwise a new session is
86             started.
87              
88             =head2 URL()
89              
90             Returns the URL of the request.
91              
92             =head1 AUTHOR
93              
94             Ryan Eatmon
95              
96             =head1 COPYRIGHT
97              
98             Copyright (c) 2003-2005 Ryan Eatmon . All rights
99             reserved. This program is free software; you can redistribute it
100             and/or modify it under the same terms as Perl itself.
101              
102             =cut
103            
104 4     4   24 use strict;
  4         8  
  4         150  
105 4     4   24 use Carp;
  4         154  
  4         276  
106 4     4   4101 use URI;
  4         11674  
  4         107  
107 4     4   3464 use URI::QueryParam;
  4         10308  
  4         126  
108 4     4   32 use URI::Escape;
  4         10  
  4         321  
109              
110 4     4   20 use vars qw ( $VERSION );
  4         10  
  4         8217  
111              
112             $VERSION = "1.0.3";
113              
114             sub new
115             {
116 6     6 0 1620 my $proto = shift;
117 6   33     47 my $class = ref($proto) || $proto;
118 6         17 my $self = { };
119            
120 6         27 bless($self, $proto);
121              
122 6         32 my (%args) = @_;
123              
124 6         31 $self->{ARGS} = \%args;
125              
126 6         23 $self->{HEADERS} = {};
127 6         20 $self->{ENV} = {};
128 6         17 $self->{COOKIES} = {};
129 6         16 $self->{FAILURE} = "";
130 6         28 $self->{CHROOT} = $self->_arg("chroot",1);
131 6         17 $self->{REQUEST} = $self->_arg("request",undef);
132 6         19 $self->{SERVER} = $self->_arg("server",undef);
133              
134 6 100       37 $self->_parse() if defined($self->{REQUEST});
135              
136 6         55 return $self;
137             }
138              
139              
140             sub Cookie
141             {
142 9     9 1 4407 my $self = shift;
143 9         20 my $cookie = shift;
144              
145 9 100       66 return $self->{COOKIES} unless defined($cookie);
146 3 100       16 return unless exists($self->{COOKIES}->{$cookie});
147 2         10 return $self->{COOKIES}->{$cookie};
148             }
149              
150              
151             sub Env
152             {
153 12     12 1 31 my $self = shift;
154 12         26 my $env = shift;
155              
156 12 100       78 return $self->{ENV} unless defined($env);
157 6 100       36 return unless exists($self->{ENV}->{$env});
158 4         28 return $self->{ENV}->{$env};
159             }
160              
161              
162             sub Header
163             {
164 10     10 1 27 my $self = shift;
165 10         18 my $header = shift;
166              
167 10 100       101 return $self->{HEADERS} unless defined($header);
168 4 100       20 return unless exists($self->{HEADERS}->{lc($header)});
169 3         17 return $self->{HEADERS}->{lc($header)};
170             }
171              
172              
173             sub Method
174             {
175 6     6 1 15 my $self = shift;
176              
177 6         46 return $self->{METHOD};
178             }
179              
180              
181             sub Path
182             {
183 6     6 1 16 my $self = shift;
184              
185 6         33 return $self->{PATH};
186             }
187              
188              
189             sub Protocol
190             {
191 0     0 0 0 my $self = shift;
192              
193 0         0 return $self->{PROTOCOL};
194             }
195              
196              
197             sub Query
198             {
199 0     0 1 0 my $self = shift;
200              
201 0         0 return $self->{QUERY};
202             }
203              
204              
205             sub Request
206             {
207 6     6 1 15 my $self = shift;
208              
209 6         63 return $self->{REQUEST};
210             }
211              
212              
213             sub Response
214             {
215 0     0 1 0 my $self = shift;
216              
217 0         0 my $response = new Net::HTTPServer::Response();
218              
219 0 0       0 if (exists($self->{SESSION}))
220             {
221 0         0 $response->Session($self->{SESSION});
222             }
223              
224 0         0 return $response;
225             }
226              
227              
228             sub Session
229             {
230 1     1 1 3 my $self = shift;
231              
232 1 50       9 return unless $self->{SERVER}->{CFG}->{SESSIONS};
233            
234 1 50       6 if (!exists($self->{SESSION}))
235             {
236 1         4 my $cookie = $self->Cookie("NETHTTPSERVERSESSION");
237            
238 1         17 $self->{SESSION} =
239             new Net::HTTPServer::Session(key=>$cookie,
240             server=>$self->{SERVER},
241             );
242             }
243              
244 1         4 return $self->{SESSION};
245             }
246              
247              
248             sub URL
249             {
250 6     6 1 16 my $self = shift;
251              
252 6         38 return $self->{URL};
253             }
254              
255              
256             ###############################################################################
257             #
258             # _arg - if the arg exists then use it, else use the default.
259             #
260             ###############################################################################
261             sub _arg
262             {
263 18     18   32 my $self = shift;
264 18         26 my $arg = shift;
265 18         26 my $default = shift;
266              
267 18 100       96 return (exists($self->{ARGS}->{$arg}) ? $self->{ARGS}->{$arg} : $default);
268             }
269              
270              
271             ###############################################################################
272             #
273             # _chroot - take the path and if we are running under chroot, massage it so
274             # that is cannot leave DOCROOT.
275             #
276             ###############################################################################
277             sub _chroot
278             {
279 5     5   209 my $self = shift;
280 5         11 my $url = shift;
281              
282 5 50       24 return $url unless $self->{CHROOT};
283            
284 5         9 my $change = 1;
285 5         17 while( $change )
286             {
287 5         7 $change = 0;
288            
289             #-----------------------------------------------------------------
290             # Look for multiple / in a row and make them one /
291             #-----------------------------------------------------------------
292 5         21 while( $url =~ s/\/\/+/\// ) { $change = 1; }
  0         0  
293            
294             #-----------------------------------------------------------------
295             # look for something/.. and remove it
296             #-----------------------------------------------------------------
297 5         18 while( $url =~ s/[^\/]+\/\.\.(\/|$)// ) { $change = 1; }
  0         0  
298              
299             #-----------------------------------------------------------------
300             # Look for ^/.. and remove it
301             #-----------------------------------------------------------------
302 5         17 while( $url =~ s/^\/?\.\.(\/|$)/\// ) { $change = 1; }
  0         0  
303            
304             #-----------------------------------------------------------------
305             # Look for /.../ and make it /
306             #-----------------------------------------------------------------
307 5         32 while( $url =~ s/(^|\/)\.+(\/|$)/\// ) { $change = 1; }
  0         0  
308             }
309              
310 5         30 return $url;
311             }
312              
313              
314             sub _failure
315             {
316 0     0   0 my $self = shift;
317              
318 0         0 return $self->{FAILURE};
319             }
320              
321              
322             sub _env
323             {
324 0     0   0 my $self = shift;
325 0         0 my $env = shift;
326 0         0 my $value = shift;
327              
328 0         0 $self->{ENV}->{$env} = $value;
329             }
330              
331              
332             sub _parse
333             {
334 5     5   12 my $self = shift;
335              
336 5         68 ($self->{METHOD},$self->{URL},$self->{PROTOCOL}) = ($self->{REQUEST} =~ /(\S+)\s+(\S+)\s+(.+?)\015?\012/s);
337            
338 5         45 my $uri = new URI($self->{URL},"http");
339              
340             #-------------------------------------------------------------------------
341             # What did they ask for?
342             #-------------------------------------------------------------------------
343 5         12130 $self->{PATH} = $self->_chroot($uri->path());
344              
345 5         322 my ($headers,$body) = ($self->{REQUEST} =~ /^(.+?)\015?\012\015?\012(.*?)$/s);
346            
347 5         13 my $last_header = "";
348 5         61 foreach my $header (split(/[\r\n]+/,$headers))
349             {
350 52         64 my $folded;
351             my $key;
352 0         0 my $value;
353            
354 52         701 ($folded,$value) = ($header =~ /^(\s*)(.+?)\s*$/);
355 52 50       129 if ($folded ne "")
356             {
357 0         0 $self->{HEADERS}->{lc($last_header)} .= $value;
358 0         0 next;
359             }
360            
361 52         482 ($key,$value) = ($header =~ /^([^\:]+?)\s*\:\s*(.+?)\s*$/);
362 52 100       130 next unless defined($key);
363              
364 47         60 $last_header = $key;
365            
366 47         130 $self->{HEADERS}->{lc($key)} = $value;
367              
368 47 50 33     141 if ((lc($key) eq "expect") && ($value ne "100-continue"))
369             {
370 0         0 $self->{FAILURE} = "expect";
371 0         0 return;
372             }
373             }
374              
375             #-------------------------------------------------------------------------
376             # Did they send any ?xxx=yy on the URL?
377             #-------------------------------------------------------------------------
378 5         42 $self->{QUERY} = $uri->query();
379 5         86 foreach my $key ($uri->query_param())
380             {
381 2         163 $self->{ENV}->{$key} = $uri->query_param($key);
382             }
383              
384             #-------------------------------------------------------------------------
385             # If this was POST, then the body contains more xxx=yyyy
386             #-------------------------------------------------------------------------
387 5 100       195 if ($self->{METHOD} eq "POST")
388             {
389 1         9 my $post_uri = new URI("?$body","http");
390              
391 1         52 foreach my $key ($post_uri->query_param())
392             {
393 2         208 $self->{ENV}->{$key} = $post_uri->query_param($key);
394             }
395             }
396              
397             #-------------------------------------------------------------------------
398             # Finally, parse out any cookies.
399             #-------------------------------------------------------------------------
400 5 100       120 if (exists($self->{HEADERS}->{cookie}))
401             {
402 3         15 foreach my $cookie ( split( /\s*;\s*/,$self->{HEADERS}->{cookie}) )
403             {
404 3         12 my ($name,$value) = split("=",$cookie,2);
405 3         14 $self->{COOKIES}->{$name} = uri_unescape($value);
406             }
407             }
408             }
409              
410              
411              
412             1;
413