9ebe51b342cb3c61b5129cb82ae6971f43d096ea
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / FastCGI.pm
1 package Catalyst::Engine::FastCGI;
2
3 use strict;
4 use base 'Catalyst::Engine::CGI';
5 eval "use FCGI";
6 die "Please install FCGI\n" if $@;
7
8 =head1 NAME
9
10 Catalyst::Engine::FastCGI - FastCGI Engine
11
12 =head1 DESCRIPTION
13
14 This is the FastCGI engine.
15
16 =head1 OVERLOADED METHODS
17
18 This class overloads some methods from C<Catalyst::Engine::CGI>.
19
20 =over 4
21
22 =item $self->run($c, $listen, { option => value, ... })
23  
24 Starts the FastCGI server.  If C<$listen> is set, then it specifies a
25 location to listen for FastCGI requests;
26
27   Form            Meaning
28   /path           listen via Unix sockets on /path
29   :port           listen via TCP on port on all interfaces
30   hostname:port   listen via TCP on port bound to hostname
31
32 Options may also be specified;
33
34   Option          Meaning
35   leave_umask     Set to 1 to disable setting umask to 0
36                   for socket open
37   nointr          Do not allow the listener to be
38                   interrupted by Ctrl+C
39   nproc           Specify a number of processes for
40                   FCGI::ProcManager
41   pidfile         Specify a filename for the pid file
42   manager         Specify a FCGI::ProcManager sub-class
43   detach          Detach from console
44
45 =cut
46
47 sub run {
48     my ( $self, $class, $listen, $options ) = @_;
49
50     my $sock;
51     if ($listen) {
52         my $old_umask = umask;
53         unless ( $options->{leave_umask} ) {
54             umask(0);
55         }
56         $sock = FCGI::OpenSocket( $listen, 100 )
57           or die "failed to open FastCGI socket; $!";
58         unless ( $options->{leave_umask} ) {
59             umask($old_umask);
60         }
61     }
62     else {
63         -S STDIN
64           or die "STDIN is not a socket; specify a listen location";
65     }
66
67     $options ||= {};
68
69     my %env;
70
71     my $request =
72       FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%env, $sock,
73         ( $options->{nointr} ? 0 : &FCGI::FAIL_ACCEPT_ON_INTR ),
74       );
75
76     my $proc_manager;
77
78     if ($listen) {
79         $options->{manager} ||= "FCGI::ProcManager";
80         $options->{nproc}   ||= 1;
81         
82         $self->daemon_fork() if $options->{detach};
83         
84         if ( $options->{manager} ) {
85             eval "use $options->{manager}; 1" or die $@;
86
87             $proc_manager
88                 = $options->{manager}->new( {
89                     n_processes => $options->{nproc},
90                     pid_fname   => $options->{pidfile},
91                 } );
92                 
93             # detach *before* the ProcManager inits
94             $self->daemon_detach() if $options->{detach};
95
96             $proc_manager->pm_manage();
97         }
98         elsif ( $options->{detach} ) {
99             $self->daemon_detach();
100         }            
101     }
102
103     while ( $request->Accept >= 0 ) {
104         $proc_manager && $proc_manager->pm_pre_dispatch();
105         $class->handle_request( env => \%env );
106         $proc_manager && $proc_manager->pm_pre_dispatch();
107     }
108 }
109
110 =item $self->write($c, $buffer)
111
112 =cut
113
114 sub write {
115     my ( $self, $c, $buffer ) = @_;
116
117     unless ( $self->{_prepared_write} ) {
118         $self->prepare_write($c);
119         $self->{_prepared_write} = 1;
120     }
121
122     # FastCGI does not stream data properly if using 'print $handle',
123     # but a syswrite appears to work properly.
124     *STDOUT->syswrite($buffer);
125 }
126
127 =item $self->daemon_fork()
128
129 Performs the first part of daemon initialisation.  Specifically,
130 forking.  STDERR, etc are still connected to a terminal.
131
132 =cut
133
134 sub daemon_fork {
135     require POSIX;
136     fork && exit;
137 }
138
139 =item $self->daemon_detach( )
140
141 Performs the second part of daemon initialisation.  Specifically,
142 disassociates from the terminal.
143
144 However, this does B<not> change the current working directory to "/",
145 as normal daemons do.  It also does not close all open file
146 descriptors (except STDIN, STDOUT and STDERR, which are re-opened from
147 F</dev/null>).
148
149 =cut
150
151 sub daemon_detach {
152     my $self = shift;
153     print "FastCGI daemon started (pid $$)\n";
154     open STDIN, "+</dev/null" or die $!;
155     open STDOUT, ">&STDIN" or die $!;
156     open STDERR, ">&STDIN" or die $!;
157     POSIX::setsid();
158 }
159
160 1;
161 __END__
162
163 =back
164
165 =head1 WEB SERVER CONFIGURATIONS
166
167 =head2 Apache 1.x, 2.x
168
169 Apache requires the mod_fastcgi module.  The following config will let Apache
170 control the running of your FastCGI processes.
171
172     # Launch the FastCGI processes
173     FastCgiIpcDir /tmp
174     FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -idle-timeout 300 -processes 5
175     
176     <VirtualHost *>
177         ScriptAlias / /var/www/MyApp/script/myapp_fastcgi.pl/
178     </VirtualHost>
179     
180 You can also tell Apache to connect to an external FastCGI server:
181
182     # Start the external server (requires FCGI::ProcManager)
183     $ script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5
184     
185     # Note that the path used in FastCgiExternalServer can be any path
186     FastCgiIpcDir /tmp
187     FastCgiExternalServer /tmp/myapp_fastcgi.pl -socket /tmp/myapp.socket
188     
189     <VirtualHost *>
190         ScriptAlias / /tmp/myapp_fastcgi.pl/
191     </VirtualHost>
192     
193 For more information on using FastCGI under Apache, visit
194 L<http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html>
195
196 =head2 Lighttpd
197
198 This configuration was tested with Lighttpd 1.4.7.
199
200     server.document-root = "/var/www/MyApp/root"
201     
202     fastcgi.server = (
203         "" => (
204             "MyApp" => (
205                 "socket"       => "/tmp/myapp.socket",
206                 "check-local"  => "disable",
207                 "bin-path"     => "/var/www/MyApp/script/myapp_fastcgi.pl",
208                 "min-procs"    => 2,
209                 "max-procs"    => 5,
210                 "idle-timeout" => 20
211             )
212         )
213     )
214     
215 You can also run your application at any non-root location.
216
217     fastcgi.server = (
218         "/myapp" => (
219             "MyApp" => (
220                 # same as above
221             )
222         )
223     )
224     
225 You can also use an external server:
226
227     # Start the external server (requires FCGI::ProcManager)
228     $ script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5
229
230     server.document-root = "/var/www/MyApp/root"
231
232     fastcgi.server = (
233         "" => (
234             "MyApp" => (
235                 "socket"      => "/tmp/myapp.socket",
236                 "check-local" => "disable"
237             )
238         )
239     )
240
241 For more information on using FastCGI under Lighttpd, visit
242 L<http://www.lighttpd.net/documentation/fastcgi.html>
243
244 =head2 IIS
245
246 It is possible to run Catalyst under IIS with FastCGI, but we do not
247 yet have detailed instructions.
248
249 =head1 SEE ALSO
250
251 L<Catalyst>, L<FCGI>.
252
253 =head1 AUTHORS
254
255 Sebastian Riedel, <sri@cpan.org>
256
257 Christian Hansen, <ch@ngmedia.com>
258
259 Andy Grundman, <andy@hybridized.org>
260
261 =head1 COPYRIGHT
262
263 This program is free software, you can redistribute it and/or modify it under
264 the same terms as Perl itself.
265
266 =cut