File Coverage

blib/lib/NetSDS/App/FCGI.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             #===============================================================================
2             #
3             # FILE: FCGI.pm
4             #
5             # DESCRIPTION: Common FastCGI applications framework
6             #
7             # NOTES: This fr
8             # AUTHOR: Michael Bochkaryov (Rattler),
9             # COMPANY: Net.Style
10             # CREATED: 15.07.2008 16:54:45 EEST
11             #===============================================================================
12              
13             =head1 NAME
14              
15             NetSDS::App::FCGI - FastCGI applications superclass
16              
17             =head1 SYNOPSIS
18              
19             # Run application
20             MyFCGI->run();
21              
22             1;
23              
24             # Application package itself
25             package MyFCGI;
26              
27             use base 'NetSDS::App::FCGI';
28              
29             sub process {
30             my ($self) = @_;
31              
32             $self->data('Hello World');
33             $self->mime('text/plain');
34             $self->charset('utf-8');
35              
36             }
37              
38              
39             =head1 DESCRIPTION
40              
41             C module contains superclass for FastCGI applications.
42             This class is based on C module and inherits all its functionality
43             like logging, configuration processing, etc.
44              
45             =cut
46              
47             package NetSDS::App::FCGI;
48              
49 2     2   15880 use 5.8.0;
  2         9  
  2         91  
50 2     2   11 use strict;
  2         3  
  2         69  
51 2     2   60 use warnings;
  2         11  
  2         71  
52              
53 2     2   11 use base 'NetSDS::App';
  2         3  
  2         278  
54              
55             use CGI::Fast;
56             use CGI::Cookie;
57              
58             use version; our $VERSION = '1.301';
59              
60             #***********************************************************************
61              
62             =head1 CLASS API
63              
64             =over
65              
66             =item B - class constructor
67              
68             Normally constructor of application framework shouldn't be invoked directly.
69              
70             =cut
71              
72             #-----------------------------------------------------------------------
73              
74             sub new {
75              
76             my ( $class, %params ) = @_;
77              
78             my $self = $class->SUPER::new(
79             cgi => undef,
80             mime => undef,
81             charset => undef,
82             data => undef,
83             redirect => undef,
84             cookie => undef,
85             status => undef,
86             headers => {},
87             %params,
88             );
89              
90             return $self;
91              
92             }
93              
94             #***********************************************************************
95              
96             =item B - accessor to CGI.pm request handler
97              
98             my $https_header = $self->cgi->https('X-Some-Header');
99              
100             =cut
101              
102             #-----------------------------------------------------------------------
103              
104             __PACKAGE__->mk_accessors('cgi');
105              
106             #***********************************************************************
107              
108             =item B - set response HTTP status
109              
110             Paramters: new status to set
111              
112             Returns: response status value
113              
114             $self->status('200 OK');
115              
116             =cut
117              
118             #-----------------------------------------------------------------------
119              
120             __PACKAGE__->mk_accessors('status');
121              
122             #***********************************************************************
123              
124             =item B - set response MIME type
125              
126             Paramters: new MIME type for response
127              
128             $self->mime('text/xml'); # output will be XML data
129              
130             =cut
131              
132             #-----------------------------------------------------------------------
133              
134             __PACKAGE__->mk_accessors('mime');
135              
136             #***********************************************************************
137              
138             =item B - set response character set if necessary
139              
140             $self->mime('text/plain');
141             $self->charset('koi8-r'); # ouput as KOI8-R text
142              
143             =cut
144              
145             #-----------------------------------------------------------------------
146              
147             __PACKAGE__->mk_accessors('charset');
148              
149             #***********************************************************************
150              
151             =item B - set response data
152              
153             Paramters: new data "as is"
154              
155             $self->mime('text/plain');
156             $self->data('Hello world!');
157              
158             =cut
159              
160             #-----------------------------------------------------------------------
161              
162             __PACKAGE__->mk_accessors('data');
163              
164             #***********************************************************************
165              
166             =item B - send HTTP redirect
167              
168             Paramters: new URL (relative or absolute)
169              
170             This method send reponse with 302 status and new location.
171              
172             if (havent_data()) {
173             $self->redirect('http://www.google.com'); # to google!
174             };
175              
176             =cut
177              
178             #-----------------------------------------------------------------------
179              
180             __PACKAGE__->mk_accessors('redirect');
181              
182             #***********************************************************************
183              
184             =item B -
185              
186             Paramters:
187              
188             Returns:
189              
190             This method provides.....
191              
192             =cut
193              
194             #-----------------------------------------------------------------------
195              
196             __PACKAGE__->mk_accessors('cookie');
197              
198             #***********************************************************************
199              
200             =item B - set/get response HTTP headers
201              
202             Paramters: new headers as hash reference
203              
204             $self->headers({
205             'X-Beer' => 'Guiness',
206             );
207              
208             =cut
209              
210             #-----------------------------------------------------------------------
211              
212             __PACKAGE__->mk_accessors('headers');
213              
214             #***********************************************************************
215              
216             =item B - main FastCGI loop
217              
218             Paramters: none
219              
220             This method implements common FastCGI (or CGI) loop.
221              
222             =cut
223              
224             #-----------------------------------------------------------------------
225              
226             sub main_loop {
227              
228             my ($self) = @_;
229              
230             $self->start();
231              
232             $SIG{TERM} = undef;
233             $SIG{INT} = undef;
234              
235             # Switch of verbosity
236             $self->{verbose} = undef;
237              
238             # Enter FastCGI loop
239             while ( $self->cgi( CGI::Fast->new() ) ) {
240              
241             # Retrieve request cookies
242             $self->_set_req_cookies();
243              
244             # Set default response parameters
245             $self->mime('text/plain'); # plain text output
246             $self->charset('utf-8'); # UTF-8 charset
247             $self->data(''); # empty string response
248             $self->status("200 OK"); # everything OK
249             $self->cookie( [] ); # no cookies
250             $self->redirect(undef); # no redirects
251              
252             # Call request processing method
253             $self->process();
254              
255             # Send 302 and Location: header if redirect
256             if ( $self->redirect ) {
257             print $self->cgi->header(
258             -cookie => $self->cookie,
259             -status => '302 Moved',
260             'Location' => $self->redirect
261             );
262              
263             } else {
264              
265             # Implement generic content output
266             use bytes;
267             print $self->cgi->header(
268             -type => $self->mime,
269             -status => $self->status,
270             -charset => $self->charset,
271             -cookie => $self->cookie,
272             -Content_length => bytes::length( $self->data ),
273             %{ $self->headers },
274             );
275             no bytes;
276              
277             # Send return data to client
278             if ( $self->data ) {
279             $| = 1; # set autoflushing mode to avoid output buffering
280             binmode STDOUT;
281             print $self->data;
282             }
283             } ## end else [ if ( $self->redirect )
284              
285             } ## end while ( $self->cgi( CGI::Fast...
286              
287             # Call finalization hooks
288             $self->stop();
289              
290             } ## end sub main_loop
291              
292             #***********************************************************************
293              
294             =item B - set cookie
295              
296             Paramters: hash (name, value, expires)
297              
298             $self->set_cookie(name => 'sessid', value => '343q5642653476', expires => '+1h');
299              
300             =cut
301              
302             #-----------------------------------------------------------------------
303              
304             sub set_cookie {
305              
306             my ( $self, %par ) = @_;
307              
308             push @{ $self->{cookie} }, $self->cgi->cookie( -name => $par{name}, -value => $par{value}, -expires => $par{expires} );
309              
310             }
311              
312             #***********************************************************************
313              
314             =item B - get cookie by name
315              
316             Paramters: cookie name
317              
318             Returns cookie value by it's name
319              
320             my $sess = $self->get_cookie('sessid');
321              
322             =cut
323              
324             #-----------------------------------------------------------------------
325              
326             sub get_cookie {
327              
328             my ( $self, $name ) = @_;
329              
330             return $self->{req_cookies}->{$name}->{value};
331              
332             }
333              
334             #***********************************************************************
335              
336             =item B - CGI request parameter
337              
338             Paramters: CGI parameter name
339              
340             Returns: CGI parameter value
341              
342             This method returns CGI parameter value by it's name.
343              
344             my $cost = $self->param('cost');
345              
346             =cut
347              
348             #-----------------------------------------------------------------------
349              
350             sub param {
351             my ( $self, @par ) = @_;
352             return $self->cgi->param(@par);
353             }
354              
355             #***********************************************************************
356              
357             =item B - CGI request parameter
358              
359             Paramters: URL parameter name
360              
361             Returns: URL parameter value
362              
363             This method works similar to B method, but returns only parameters
364             from the query string.
365              
366             my $action = $self->url_param('a');
367              
368             =cut
369              
370             #-----------------------------------------------------------------------
371              
372             sub url_param {
373             my ( $self, @par ) = @_;
374             return $self->cgi->url_param(@par);
375             }
376              
377             #***********************************************************************
378              
379             =item B - request HTTP header
380              
381             Paramters: request header name
382              
383             Returns: header value
384              
385             This method returns HTTP request header value by name.
386              
387             my $beer = $self->http('X-Beer');
388              
389             =cut
390              
391             #-----------------------------------------------------------------------
392              
393             sub http {
394              
395             my $self = shift;
396             my $par = shift;
397              
398             return $self->cgi->http($par);
399             }
400              
401             #***********************************************************************
402              
403             =item B - request HTTPS header
404              
405             This method returns HTTPS request header value by name and is almost
406             the same as http() method except of it works with SSL requests.
407              
408             my $beer = $self->https('X-Beer');
409              
410             =cut
411              
412             #-----------------------------------------------------------------------
413              
414             sub https {
415              
416             my $self = shift;
417             my $par = shift;
418              
419             return $self->cgi->https($par);
420             }
421              
422             #***********************************************************************
423              
424             =item B - get raw cookie data
425              
426             Just proxying C method from CGI.pm
427              
428             =cut
429              
430             #-----------------------------------------------------------------------
431              
432             sub raw_cookie {
433             my ($self) = @_;
434              
435             return $self->cgi->raw_cookie;
436             }
437              
438             #**************************************************************************
439              
440             =item B - User-Agent request header
441              
442             my $ua_info = $self->user_agent();
443              
444             =cut
445              
446             #-----------------------------------------------------------------------
447             sub user_agent {
448             my ($self) = @_;
449              
450             return $self->cgi->user_agent;
451             }
452              
453             #***********************************************************************
454              
455             =item B - HTTP request method
456              
457             if ($self->request_method eq 'POST') {
458             $self->log("info", "Something POST'ed from client");
459             }
460              
461             =cut
462              
463             #-----------------------------------------------------------------------
464              
465             sub request_method {
466             my ($self) = @_;
467              
468             return $self->cgi->request_method;
469             }
470              
471             #***********************************************************************
472              
473             =item B - CGI script name
474              
475             Returns: script name from CGI.pm
476              
477             =cut
478              
479             #-----------------------------------------------------------------------
480              
481             sub script_name {
482              
483             my ($self) = @_;
484              
485             return $self->cgi->script_name();
486             }
487              
488             #***********************************************************************
489              
490             =item B - get PATH_INFO value
491              
492             if ($self->path_info eq '/help') {
493             $self->data('Help yourself');
494             }
495              
496             =cut
497              
498             #-----------------------------------------------------------------------
499              
500             sub path_info {
501              
502             my ($self) = @_;
503              
504             return $self->cgi->path_info();
505             }
506              
507             #***********************************************************************
508              
509             =item B - remote (client) host name
510              
511             warn "Client from: " . $self->remote_host();
512              
513             =cut
514              
515             #-----------------------------------------------------------------------
516              
517             sub remote_host {
518              
519             my ($self) = @_;
520              
521             return $self->cgi->remote_host();
522              
523             }
524              
525             #***********************************************************************
526              
527             =item B - remote (client) IP address
528              
529             Returns: IP address of client from REMOTE_ADDR environment
530              
531             if ($self->remote_addr eq '10.0.0.1') {
532             $self->data('Welcome people from our gateway!');
533             }
534              
535             =cut
536              
537             #-----------------------------------------------------------------------
538              
539             sub remote_addr {
540              
541             my ($self) = @_;
542              
543             return $ENV{REMOTE_ADDR};
544             }
545              
546             #***********************************************************************
547              
548             =item B<_set_req_cookies()> - fetching request cookies (internal method)
549              
550             Fetching cookies from HTTP request to object C variable.
551              
552             =cut
553              
554             #-----------------------------------------------------------------------
555              
556             sub _set_req_cookies {
557             my ($self) = @_;
558              
559             my %cookies = CGI::Cookie->fetch();
560             $self->{req_cookies} = \%cookies;
561              
562             return 1;
563             }
564              
565             1;
566              
567             __END__