1 Subject: [PATCH] gitweb: support automatic FCGI detection
3 Add support for a new configuration option '$auto_fcgi' and when true
4 automatically activate FCGI mode when getsockname succeeds on STDIN
5 (and STDIN is on fd 0) and getpeername returns ENOTCONN.
7 Enabling this feature allows the same configuration to be used for
8 both non-FCGI (i.e. regular CGI mode) and FCGI mode operation.
10 This feature is currently opt-in only. Because although extremely
11 unlikely, it's certainly feasible for gitweb to be executed with STDIN
12 set to a socket in listen mode even though gitweb itself is expected
13 to not actually run in FCGI mode. And someday pigs might fly.
15 Signed-off-by: Kyle J. McKay <mackyle@gmail.com>
17 Documentation/gitweb.conf.txt | 5 +++
18 gitweb/gitweb.perl | 79 ++++++++++++++++++++++++++++++-------------
19 2 files changed, 60 insertions(+), 24 deletions(-)
21 diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
22 index bad4bfd7..a65f19dc 100644
23 --- a/Documentation/gitweb.conf.txt
24 +++ b/Documentation/gitweb.conf.txt
25 @@ -629,6 +629,11 @@ This variable matters only when using persistent web environments that
26 serve multiple requests using single gitweb instance, like mod_perl,
30 + If true and STDIN has fileno 0 and getsockname succeeds and getpeername
31 + fails with ENOTCONN, FCGI mode will be activated automatically just the
32 + same way as though the '--fcgi' option was given.
37 diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
38 index 5c2ab6ac..15a8bcbc 100755
39 --- a/gitweb/gitweb.perl
40 +++ b/gitweb/gitweb.perl
41 @@ -452,7 +452,8 @@ our %feature = (
42 # Note that you will need to change the default location of CSS,
43 # favicon, logo and possibly other files to an absolute URL. Also,
44 # if gitweb.cgi serves as your indexfile, you will need to force
45 - # $my_uri to contain the script name in your $GITWEB_CONFIG.
46 + # $my_uri to contain the script name in your $GITWEB_CONFIG (and you
47 + # will also likely want to set $home_link if you're setting $my_uri).
51 @@ -761,6 +762,11 @@ sub filter_and_validate_refs {
52 # if it is true then gitweb config would be run for each request.
53 our $per_request_config = 1;
55 +# If true and fileno STDIN is 0 and getsockname succeeds and getpeername fails
56 +# with ENOTCONN, then FCGI mode will be activated automatically in just the
57 +# same way as though the --fcgi option had been given instead.
60 # read and parse gitweb config file given by its parameter.
61 # returns true on success, false on recoverable error, allowing
62 # to chain this subroutine, using first file that exists.
63 @@ -1296,6 +1302,7 @@ sub reset_timer {
66 our $first_request = 1;
67 +our $evaluate_uri_force = undef;
71 @@ -1312,10 +1319,7 @@ EOT
75 - if ($first_request) {
76 - evaluate_gitweb_config();
77 - evaluate_git_version();
79 + &$evaluate_uri_force() if $evaluate_uri_force;
80 if ($per_request_config) {
81 if (ref($per_request_config) eq 'CODE') {
82 $per_request_config->();
83 @@ -1342,10 +1346,24 @@ our $is_last_request = sub { 1 };
84 our ($pre_dispatch_hook, $post_dispatch_hook, $pre_listen_hook);
88 +our $fcgi_nproc_active = 0;
91 + my $stdinfno = fileno STDIN;
92 + return 0 unless defined $stdinfno && $stdinfno == 0;
93 + return 0 unless getsockname STDIN;
94 + return 0 if getpeername STDIN;
95 + return $!{ENOTCONN}?1:0;
97 sub configure_as_fcgi {
98 + return if $fcgi_mode;
101 our $CGI = 'CGI::Fast';
104 + $first_request = 0;
105 my $request_number = 0;
106 # let each child service 100 requests
107 our $is_last_request = sub { ++$request_number >= 100 };
108 @@ -1353,24 +1371,29 @@ sub configure_as_fcgi {
110 my $script_name = $ENV{'SCRIPT_NAME'} || $ENV{'SCRIPT_FILENAME'} || __FILE__;
112 - if $script_name =~ /\.fcgi$/;
113 + if $script_name =~ /\.fcgi$/ || ($auto_fcgi && is_fcgi());
115 - return unless (@ARGV);
117 - require Getopt::Long;
118 - Getopt::Long::GetOptions(
119 - 'fastcgi|fcgi|f' => \&configure_as_fcgi,
120 - 'nproc|n=i' => sub {
121 - my ($arg, $val) = @_;
122 - return unless eval { require FCGI::ProcManager; 1; };
123 - my $proc_manager = FCGI::ProcManager->new({
124 - n_processes => $val,
126 - our $pre_listen_hook = sub { $proc_manager->pm_manage() };
127 - our $pre_dispatch_hook = sub { $proc_manager->pm_pre_dispatch() };
128 - our $post_dispatch_hook = sub { $proc_manager->pm_post_dispatch() };
131 + my $nproc_sub = sub {
132 + my ($arg, $val) = @_;
133 + return unless eval { require FCGI::ProcManager; 1; };
134 + $fcgi_nproc_active = 1;
135 + my $proc_manager = FCGI::ProcManager->new({
136 + n_processes => $val,
138 + our $pre_listen_hook = sub { $proc_manager->pm_manage() };
139 + our $pre_dispatch_hook = sub { $proc_manager->pm_pre_dispatch() };
140 + our $post_dispatch_hook = sub { $proc_manager->pm_post_dispatch() };
143 + require Getopt::Long;
144 + Getopt::Long::GetOptions(
145 + 'fastcgi|fcgi|f' => \&configure_as_fcgi,
146 + 'nproc|n=i' => $nproc_sub,
149 + if (!$fcgi_nproc_active && defined $ENV{'GITWEB_FCGI_NPROC'} && $ENV{'GITWEB_FCGI_NPROC'} =~ /^\d+$/) {
150 + &$nproc_sub('nproc', $ENV{'GITWEB_FCGI_NPROC'});
154 # Any "our" variable that could possibly influence correct handling of
155 @@ -1392,9 +1415,17 @@ sub _reset_globals {
161 + evaluate_gitweb_config();
162 + evaluate_git_version();
163 + my ($ml, $mi, $bu, $hl, $subroutine) = ($my_url, $my_uri, $base_url, $home_link, '');
164 + $subroutine .= '$my_url = $ml;' if defined $my_url && $my_url ne '';
165 + $subroutine .= '$my_uri = $mi;' if defined $my_uri; # this one can be ""
166 + $subroutine .= '$base_url = $bu;' if defined $base_url && $base_url ne '';
167 + $subroutine .= '$home_link = $hl;' if defined $home_link && $home_link ne '';
168 + $evaluate_uri_force = eval "sub {$subroutine}" if $subroutine;