Fix IIS FastCGI support as-per we do with lighty + refactroing and tests.
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / FastCGI.pm
CommitLineData
d1d9793f 1package Catalyst::Engine::FastCGI;
ffb41d94 2
3use strict;
fbcc39ad 4use base 'Catalyst::Engine::CGI';
6f409682 5eval "use FCGI";
500a1679 6die "Unable to load the FCGI module, you may need to install it:\n$@\n" if $@;
ffb41d94 7
8=head1 NAME
9
fbcc39ad 10Catalyst::Engine::FastCGI - FastCGI Engine
ffb41d94 11
12=head1 DESCRIPTION
13
fbcc39ad 14This is the FastCGI engine.
ffb41d94 15
e2fd5b5f 16=head1 OVERLOADED METHODS
17
fbcc39ad 18This class overloads some methods from C<Catalyst::Engine::CGI>.
e2fd5b5f 19
b5ecfcf0 20=head2 $self->run($c, $listen, { option => value, ... })
5898abae 21
22Starts the FastCGI server. If C<$listen> is set, then it specifies a
23location to listen for FastCGI requests;
24
b799b493 25=over 4
26
27=item /path
28
29listen via Unix sockets on /path
30
31=item :port
32
33listen via TCP on port on all interfaces
34
35=item hostname:port
36
37listen via TCP on port bound to hostname
38
39=back
5898abae 40
41Options may also be specified;
42
b799b493 43=over 4
44
45=item leave_umask
46
47Set to 1 to disable setting umask to 0 for socket open =item nointr
48
49Do not allow the listener to be interrupted by Ctrl+C
50
51=item nproc
52
53Specify a number of processes for FCGI::ProcManager
54
55=item pidfile
56
57Specify a filename for the pid file
58
59=item manager
60
61Specify a FCGI::ProcManager sub-class
62
63=item detach
64
65Detach from console
66
67=item keep_stderr
68
69Send STDERR to STDOUT instead of the webserver
70
71=back
e2fd5b5f 72
73=cut
74
fbcc39ad 75sub run {
5898abae 76 my ( $self, $class, $listen, $options ) = @_;
77
5db46287 78 my $sock = 0;
5898abae 79 if ($listen) {
80 my $old_umask = umask;
81 unless ( $options->{leave_umask} ) {
82 umask(0);
83 }
84 $sock = FCGI::OpenSocket( $listen, 100 )
85 or die "failed to open FastCGI socket; $!";
86 unless ( $options->{leave_umask} ) {
87 umask($old_umask);
88 }
89 }
6f2e0021 90 elsif ( $^O ne 'MSWin32' ) {
5898abae 91 -S STDIN
92 or die "STDIN is not a socket; specify a listen location";
93 }
94
95 $options ||= {};
6f409682 96
84528885 97 my %env;
6fc58422 98 my $error = \*STDERR; # send STDERR to the web server
99 $error = \*STDOUT # send STDERR to stdout (a logfile)
85d9fce6 100 if $options->{keep_stderr}; # (if asked to)
6fc58422 101
5898abae 102 my $request =
6fc58422 103 FCGI::Request( \*STDIN, \*STDOUT, $error, \%env, $sock,
5898abae 104 ( $options->{nointr} ? 0 : &FCGI::FAIL_ACCEPT_ON_INTR ),
105 );
106
107 my $proc_manager;
6f409682 108
109 if ($listen) {
526b698a 110 $options->{manager} ||= "FCGI::ProcManager";
111 $options->{nproc} ||= 1;
b5ecfcf0 112
526b698a 113 $self->daemon_fork() if $options->{detach};
b5ecfcf0 114
526b698a 115 if ( $options->{manager} ) {
116 eval "use $options->{manager}; 1" or die $@;
117
b5ecfcf0 118 $proc_manager = $options->{manager}->new(
119 {
526b698a 120 n_processes => $options->{nproc},
121 pid_fname => $options->{pidfile},
b5ecfcf0 122 }
123 );
124
526b698a 125 # detach *before* the ProcManager inits
126 $self->daemon_detach() if $options->{detach};
127
128 $proc_manager->pm_manage();
dc2fc680 129 }
526b698a 130 elsif ( $options->{detach} ) {
131 $self->daemon_detach();
b5ecfcf0 132 }
5898abae 133 }
e2fd5b5f 134
fbcc39ad 135 while ( $request->Accept >= 0 ) {
5898abae 136 $proc_manager && $proc_manager->pm_pre_dispatch();
9b8ed9d1 137
138 $self->_fix_env( \%env );
d7334071 139
84528885 140 $class->handle_request( env => \%env );
d7334071 141
9f778270 142 $proc_manager && $proc_manager->pm_post_dispatch();
fbcc39ad 143 }
e2fd5b5f 144}
145
b5ecfcf0 146=head2 $self->write($c, $buffer)
e2fd5b5f 147
148=cut
149
fbcc39ad 150sub write {
151 my ( $self, $c, $buffer ) = @_;
4f5ebacd 152
fbcc39ad 153 unless ( $self->{_prepared_write} ) {
4f5ebacd 154 $self->prepare_write($c);
fbcc39ad 155 $self->{_prepared_write} = 1;
156 }
e512dd24 157
158 # XXX: We can't use Engine's write() method because syswrite
159 # appears to return bogus values instead of the number of bytes
160 # written: http://www.fastcgi.com/om_archive/mail-archive/0128.html
161
162 # Prepend the headers if they have not yet been sent
163 if ( my $headers = delete $self->{_header_buf} ) {
164 $buffer = $headers . $buffer;
165 }
4f5ebacd 166
fbcc39ad 167 # FastCGI does not stream data properly if using 'print $handle',
168 # but a syswrite appears to work properly.
4f5ebacd 169 *STDOUT->syswrite($buffer);
e2fd5b5f 170}
171
b5ecfcf0 172=head2 $self->daemon_fork()
526b698a 173
174Performs the first part of daemon initialisation. Specifically,
175forking. STDERR, etc are still connected to a terminal.
176
177=cut
178
179sub daemon_fork {
180 require POSIX;
181 fork && exit;
182}
183
b5ecfcf0 184=head2 $self->daemon_detach( )
526b698a 185
186Performs the second part of daemon initialisation. Specifically,
187disassociates from the terminal.
188
189However, this does B<not> change the current working directory to "/",
190as normal daemons do. It also does not close all open file
191descriptors (except STDIN, STDOUT and STDERR, which are re-opened from
192F</dev/null>).
193
194=cut
195
196sub daemon_detach {
197 my $self = shift;
198 print "FastCGI daemon started (pid $$)\n";
b5ecfcf0 199 open STDIN, "+</dev/null" or die $!;
200 open STDOUT, ">&STDIN" or die $!;
201 open STDERR, ">&STDIN" or die $!;
526b698a 202 POSIX::setsid();
203}
204
9b8ed9d1 205=head2 $self->_fix_env( $env )
206
207Adjusts the environment variables when necessary.
208
209=cut
210
211sub _fix_env
212{
213 my $self = shift;
214 my $env = shift;
215
216 return unless ( $env->{SERVER_SOFTWARE} );
217
218 # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME
219 # http://lists.scsys.co.uk/pipermail/catalyst/2006-June/008361.html
220 # Thanks to Mark Blythe for this fix
221 if ( $env->{SERVER_SOFTWARE} =~ /lighttpd/ ) {
222 $env->{PATH_INFO} ||= delete $env->{SCRIPT_NAME};
223 }
224 # Fix the environment variables PATH_INFO and SCRIPT_NAME when running under IIS 6.0
225 elsif ( $env->{SERVER_SOFTWARE} =~ /IIS\/6.0/ ) {
226 my @script_name = split(m!/!, $env->{PATH_INFO});
227 my @path_translated = split(m!/|\\\\?!, $env->{PATH_TRANSLATED});
228 my @path_info;
229
230 while ($script_name[$#script_name] eq $path_translated[$#path_translated]) {
231 pop(@path_translated);
232 unshift(@path_info, pop(@script_name));
233 }
234
235 unshift(@path_info, '', '');
236
237 $env->{PATH_INFO} = join('/', @path_info);
238 $env->{SCRIPT_NAME} = join('/', @script_name);
239 }
240}
241
198b0efa 2421;
243__END__
244
198b0efa 245=head1 WEB SERVER CONFIGURATIONS
246
d7d72ad9 247=head2 Standalone FastCGI Server
248
249In server mode the application runs as a standalone server and accepts
250connections from a web server. The application can be on the same machine as
251the web server, on a remote machine, or even on multiple remote machines.
252Advantages of this method include running the Catalyst application as a
253different user than the web server, and the ability to set up a scalable
254server farm.
198b0efa 255
d7d72ad9 256To start your application in server mode, install the FCGI::ProcManager
257module and then use the included fastcgi.pl script.
198b0efa 258
d7d72ad9 259 $ script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5
198b0efa 260
d7d72ad9 261Command line options for fastcgi.pl include:
262
263 -d -daemon Daemonize the server.
264 -p -pidfile Write a pidfile with the pid of the process manager.
265 -l -listen Listen on a socket path, hostname:port, or :port.
266 -n -nproc The number of processes started to handle requests.
198b0efa 267
d7d72ad9 268See below for the specific web server configurations for using the external
269server.
198b0efa 270
d7d72ad9 271=head2 Apache 1.x, 2.x
272
273Apache requires the mod_fastcgi module. The same module supports both
274Apache 1 and 2.
275
276There are three ways to run your application under FastCGI on Apache: server,
277static, and dynamic.
278
279=head3 Standalone server mode
280
3f0911d3 281 FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
282 Alias /myapp/ /tmp/myapp/myapp.fcgi/
d7d72ad9 283
284 # Or, run at the root
3f0911d3 285 Alias / /tmp/myapp.fcgi/
d7d72ad9 286
287 # Optionally, rewrite the path when accessed without a trailing slash
288 RewriteRule ^/myapp$ myapp/ [R]
289
3f0911d3 290
291The FastCgiExternalServer directive tells Apache that when serving
292/tmp/myapp to use the FastCGI application listenting on the socket
293/tmp/mapp.socket. Note that /tmp/myapp.fcgi does not need to exist --
294it's a virtual file name. With some versions of C<mod_fastcgi> or
295C<mod_fcgid>, you can use any name you like, but most require that the
296virtual filename end in C<.fcgi>.
d7d72ad9 297
298It's likely that Apache is not configured to serve files in /tmp, so the
299Alias directive maps the url path /myapp/ to the (virtual) file that runs the
300FastCGI application. The trailing slashes are important as their use will
301correctly set the PATH_INFO environment variable used by Catalyst to
302determine the request path. If you would like to be able to access your app
303without a trailing slash (http://server/myapp), you can use the above
304RewriteRule directive.
305
306=head3 Static mode
307
308The term 'static' is misleading, but in static mode Apache uses its own
309FastCGI Process Manager to start the application processes. This happens at
310Apache startup time. In this case you do not run your application's
311fastcgi.pl script -- that is done by Apache. Apache then maps URIs to the
312FastCGI script to run your application.
313
314 FastCgiServer /path/to/myapp/script/myapp_fastcgi.pl -processes 3
315 Alias /myapp/ /path/to/myapp/script/myapp_fastcgi.pl/
198b0efa 316
d7d72ad9 317FastCgiServer tells Apache to start three processes of your application at
318startup. The Alias command maps a path to the FastCGI application. Again,
319the trailing slashes are important.
198b0efa 320
d7d72ad9 321=head3 Dynamic mode
322
323In FastCGI dynamic mode, Apache will run your application on demand,
324typically by requesting a file with a specific extension (e.g. .fcgi). ISPs
325often use this type of setup to provide FastCGI support to many customers.
326
327In this mode it is often enough to place or link your *_fastcgi.pl script in
328your cgi-bin directory with the extension of .fcgi. In dynamic mode Apache
329must be able to run your application as a CGI script so ExecCGI must be
330enabled for the directory.
331
332 AddHandler fastcgi-script .fcgi
333
334The above tells Apache to run any .fcgi file as a FastCGI application.
335
336Here is a complete example:
337
338 <VirtualHost *:80>
339 ServerName www.myapp.com
340 DocumentRoot /path/to/MyApp
341
342 # Allow CGI script to run
343 <Directory /path/to/MyApp>
344 Options +ExecCGI
345 </Directory>
346
347 # Tell Apache this is a FastCGI application
348 <Files myapp_fastcgi.pl>
349 SetHandler fastcgi-script
350 </Files>
198b0efa 351 </VirtualHost>
d7d72ad9 352
353Then a request for /script/myapp_fastcgi.pl will run the
354application.
198b0efa 355
356For more information on using FastCGI under Apache, visit
357L<http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html>
358
25f55123 359=head3 Authorization header with mod_fastcgi or mod_cgi
360
361By default, mod_fastcgi/mod_cgi do not pass along the Authorization header,
362so modules like C<Catalyst::Plugin::Authentication::Credential::HTTP> will
363not work. To enable pass-through of this header, add the following
364mod_rewrite directives:
365
366 RewriteCond %{HTTP:Authorization} ^(.+)
367 RewriteRule ^(.*)$ $1 [E=HTTP_AUTHORIZATION:%1,PT]
368
198b0efa 369=head2 Lighttpd
370
d7d72ad9 371These configurations were tested with Lighttpd 1.4.7.
372
373=head3 Standalone server mode
374
375 server.document-root = "/var/www/MyApp/root"
376
377 fastcgi.server = (
378 "" => (
379 "MyApp" => (
380 "socket" => "/tmp/myapp.socket",
381 "check-local" => "disable"
382 )
383 )
384 )
385
386=head3 Static mode
198b0efa 387
388 server.document-root = "/var/www/MyApp/root"
389
390 fastcgi.server = (
391 "" => (
392 "MyApp" => (
393 "socket" => "/tmp/myapp.socket",
394 "check-local" => "disable",
395 "bin-path" => "/var/www/MyApp/script/myapp_fastcgi.pl",
396 "min-procs" => 2,
397 "max-procs" => 5,
398 "idle-timeout" => 20
399 )
400 )
401 )
402
d7d72ad9 403Note that in newer versions of lighttpd, the min-procs and idle-timeout
404values are disabled. The above example would start 5 processes.
25810c41 405
d7d72ad9 406=head3 Non-root configuration
25810c41 407
d7d72ad9 408You can also run your application at any non-root location with either of the
85c12bce 409above modes. Note the required mod_rewrite rule.
198b0efa 410
85c12bce 411 url.rewrite = ( "myapp\$" => "myapp/" )
198b0efa 412 fastcgi.server = (
d7d72ad9 413 "/myapp" => (
198b0efa 414 "MyApp" => (
d7d72ad9 415 # same as above
198b0efa 416 )
417 )
418 )
419
420For more information on using FastCGI under Lighttpd, visit
421L<http://www.lighttpd.net/documentation/fastcgi.html>
422
423=head2 IIS
424
425It is possible to run Catalyst under IIS with FastCGI, but we do not
426yet have detailed instructions.
427
fbcc39ad 428=head1 SEE ALSO
e2fd5b5f 429
fbcc39ad 430L<Catalyst>, L<FCGI>.
cd3bb248 431
fbcc39ad 432=head1 AUTHORS
ffb41d94 433
0bf7ab71 434Catalyst Contributors, see Catalyst.pm
ffb41d94 435
d7d72ad9 436=head1 THANKS
437
438Bill Moseley, for documentation updates and testing.
439
ffb41d94 440=head1 COPYRIGHT
441
442This program is free software, you can redistribute it and/or modify it under
443the same terms as Perl itself.
444
445=cut