Merge branch 'jn/gitweb-fastcgi'

* jn/gitweb-fastcgi:
  gitweb: Run in FastCGI mode if gitweb script has .fcgi extension
  gitweb: Add support for FastCGI, using CGI::Fast
  gitweb: Put all per-connection code in run() subroutine
This commit is contained in:
Junio C Hamano 2010-06-21 06:02:42 -07:00
commit a031d76eeb

View File

@ -28,8 +28,12 @@ BEGIN {
CGI->compile() if $ENV{'MOD_PERL'}; CGI->compile() if $ENV{'MOD_PERL'};
} }
our $cgi = new CGI;
our $version = "++GIT_VERSION++"; our $version = "++GIT_VERSION++";
our ($my_url, $my_uri, $base_url, $path_info, $home_link);
sub evaluate_uri {
our $cgi;
our $my_url = $cgi->url(); our $my_url = $cgi->url();
our $my_uri = $cgi->url(-absolute => 1); our $my_uri = $cgi->url(-absolute => 1);
@ -58,6 +62,10 @@ if ($path_info) {
} }
} }
# target of the home link on top of all pages
our $home_link = $my_uri || "/";
}
# core git executable to use # core git executable to use
# this can just be "git" if your webserver has a sensible PATH # this can just be "git" if your webserver has a sensible PATH
our $GIT = "++GIT_BINDIR++/git"; our $GIT = "++GIT_BINDIR++/git";
@ -70,9 +78,6 @@ our $projectroot = "++GITWEB_PROJECTROOT++";
# the number is relative to the projectroot # the number is relative to the projectroot
our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++"; our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++";
# target of the home link on top of all pages
our $home_link = $my_uri || "/";
# string of the home link on top of all pages # string of the home link on top of all pages
our $home_link_str = "++GITWEB_HOME_LINK_STR++"; our $home_link_str = "++GITWEB_HOME_LINK_STR++";
@ -566,6 +571,8 @@ sub filter_snapshot_fmts {
!$known_snapshot_formats{$_}{'disabled'}} @fmts; !$known_snapshot_formats{$_}{'disabled'}} @fmts;
} }
our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM);
sub evaluate_gitweb_config {
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++"; our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
# die if there are errors parsing config file # die if there are errors parsing config file
@ -576,6 +583,7 @@ if (-e $GITWEB_CONFIG) {
do $GITWEB_CONFIG_SYSTEM; do $GITWEB_CONFIG_SYSTEM;
die $@ if $@; die $@ if $@;
} }
}
# Get loadavg of system, to compare against $maxload. # Get loadavg of system, to compare against $maxload.
# Currently it requires '/proc/loadavg' present to get loadavg; # Currently it requires '/proc/loadavg' present to get loadavg;
@ -600,14 +608,17 @@ sub get_loadavg {
} }
# version of the core git binary # version of the core git binary
our $git_version;
sub evaluate_git_version {
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown"; our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
$number_of_git_cmds++; $number_of_git_cmds++;
}
$projects_list ||= $projectroot; sub check_loadavg {
if (defined $maxload && get_loadavg() > $maxload) { if (defined $maxload && get_loadavg() > $maxload) {
die_error(503, "The load average on the server is too high"); die_error(503, "The load average on the server is too high");
} }
}
# ====================================================================== # ======================================================================
# input validation and dispatch # input validation and dispatch
@ -693,6 +704,9 @@ our %allowed_options = (
# should be single values, but opt can be an array. We should probably # should be single values, but opt can be an array. We should probably
# build an array of parameters that can be multi-valued, but since for the time # build an array of parameters that can be multi-valued, but since for the time
# being it's only this one, we just single it out # being it's only this one, we just single it out
sub evaluate_query_params {
our $cgi;
while (my ($name, $symbol) = each %cgi_param_mapping) { while (my ($name, $symbol) = each %cgi_param_mapping) {
if ($symbol eq 'opt') { if ($symbol eq 'opt') {
$input_params{$name} = [ $cgi->param($symbol) ]; $input_params{$name} = [ $cgi->param($symbol) ];
@ -700,6 +714,7 @@ while (my ($name, $symbol) = each %cgi_param_mapping) {
$input_params{$name} = $cgi->param($symbol); $input_params{$name} = $cgi->param($symbol);
} }
} }
}
# now read PATH_INFO and update the parameter list for missing parameters # now read PATH_INFO and update the parameter list for missing parameters
sub evaluate_path_info { sub evaluate_path_info {
@ -844,8 +859,11 @@ sub evaluate_path_info {
} }
} }
} }
evaluate_path_info();
our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_base,
$hash_parent_base, @extra_options, $page, $searchtype, $search_use_regexp,
$searchtext, $search_regexp);
sub evaluate_and_validate_params {
our $action = $input_params{'action'}; our $action = $input_params{'action'};
if (defined $action) { if (defined $action) {
if (!validate_action($action)) { if (!validate_action($action)) {
@ -943,11 +961,16 @@ if (defined $searchtext) {
} }
$search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
} }
}
# path to the current git repository # path to the current git repository
our $git_dir; our $git_dir;
$git_dir = "$projectroot/$project" if $project; sub evaluate_git_dir {
our $git_dir = "$projectroot/$project" if $project;
}
our (@snapshot_fmts, $git_avatar);
sub configure_gitweb_features {
# list of supported snapshot formats # list of supported snapshot formats
our @snapshot_fmts = gitweb_get_feature('snapshot'); our @snapshot_fmts = gitweb_get_feature('snapshot');
@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts); @snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
@ -964,6 +987,7 @@ if ($git_avatar eq 'gravatar') {
} else { } else {
$git_avatar = ''; $git_avatar = '';
} }
}
# custom error handler: 'die <message>' is Internal Server Error # custom error handler: 'die <message>' is Internal Server Error
sub handle_errors_html { sub handle_errors_html {
@ -981,6 +1005,7 @@ sub handle_errors_html {
set_message(\&handle_errors_html); set_message(\&handle_errors_html);
# dispatch # dispatch
sub dispatch {
if (!defined $action) { if (!defined $action) {
if (defined $hash) { if (defined $hash) {
$action = git_get_type($hash); $action = git_get_type($hash);
@ -1000,8 +1025,89 @@ if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
die_error(400, "Project needed"); die_error(400, "Project needed");
} }
$actions{$action}->(); $actions{$action}->();
}
sub run_request {
our $t0 = [Time::HiRes::gettimeofday()]
if defined $t0;
evaluate_uri();
evaluate_gitweb_config();
evaluate_git_version();
check_loadavg();
# $projectroot and $projects_list might be set in gitweb config file
$projects_list ||= $projectroot;
evaluate_query_params();
evaluate_path_info();
evaluate_and_validate_params();
evaluate_git_dir();
configure_gitweb_features();
dispatch();
}
our $is_last_request = sub { 1 };
our ($pre_dispatch_hook, $post_dispatch_hook, $pre_listen_hook);
our $CGI = 'CGI';
our $cgi;
sub configure_as_fcgi {
require CGI::Fast;
our $CGI = 'CGI::Fast';
my $request_number = 0;
# let each child service 100 requests
our $is_last_request = sub { ++$request_number > 100 };
}
sub evaluate_argv {
my $script_name = $ENV{'SCRIPT_NAME'} || $ENV{'SCRIPT_FILENAME'} || __FILE__;
configure_as_fcgi()
if $script_name =~ /\.fcgi$/;
return unless (@ARGV);
require Getopt::Long;
Getopt::Long::GetOptions(
'fastcgi|fcgi|f' => \&configure_as_fcgi,
'nproc|n=i' => sub {
my ($arg, $val) = @_;
return unless eval { require FCGI::ProcManager; 1; };
my $proc_manager = FCGI::ProcManager->new({
n_processes => $val,
});
our $pre_listen_hook = sub { $proc_manager->pm_manage() };
our $pre_dispatch_hook = sub { $proc_manager->pm_pre_dispatch() };
our $post_dispatch_hook = sub { $proc_manager->pm_post_dispatch() };
},
);
}
sub run {
evaluate_argv();
$pre_listen_hook->()
if $pre_listen_hook;
REQUEST:
while ($cgi = $CGI->new()) {
$pre_dispatch_hook->()
if $pre_dispatch_hook;
run_request();
$pre_dispatch_hook->()
if $post_dispatch_hook;
last REQUEST if ($is_last_request->());
}
DONE_GITWEB: DONE_GITWEB:
1; 1;
}
run();
## ====================================================================== ## ======================================================================
## action links ## action links