From 6c476e790ce56a207f4f76ecc7b1de9a7c00ff35 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" <mackyle@gmail.com> Date: Wed, 27 Jan 2021 23:25:22 -0700 Subject: [PATCH] bin/gitweb-gc.sh: add gitweb FastCGI utility script The FastCGI specification can still be found at: https://web.archive.org/web/20160310000121/http://www.fastcgi.com/devkit/doc/fcgi-spec.html or alternatively archived here: https://fast-cgi.github.io/ Section "7. Errors" states: > A FastCGI application exits with zero status to indicate that it > terminated on purpose, e.g. in order to perform a crude form of > garbage collection. A FastCGI application that exits with nonzero > status is assumed to have crashed. The gitweb.cgi application running in FastCGI mode falls into the category of "application exits with zero status to indicate that it terminated on purpose, e.g. in order to perform a crude form of garbage collection." The standard gitweb.cgi when running in FastCGI mode always exits with "zero status" after serving 100 requests. While Apache's mod_fcgid can easily be configured to expect this behavior (via the `FcgidCmdOptions /gitweb.cgi MaxRequestsPerProcess 100` configuration line), mod_fcgid handles unexpected "zero status" exits just fine as well and simply restarts the cgi as needed. Some other web servers that provide FastCGI support are not nearly as forgiving (they do not handle the unexpected "zero status" exit) or as accomodating (they do not have the equivalent of the `MaxRequestsPerProcess` configuration option). For example, lighttpd behaves very badly when gitweb exits with the unexpected "zero status" after 100 requests and then proceeds to drop and fail any outstanding requests to that FastCGI application before it manages to restart it. This causes a bad user experience as every so often requests will fail, but then succeed when retried. To accomodate these web servers that poorly implement the FastCGI specification while allowing gitweb.cgi running in FastCGI mode to work without intermittent failures, provide an intermediary "helper" script that conceals the "zero status" (aka "crude form of garbage collection") exits from the web server and seemlessly restarts a new copy of gitweb.cgi. This allows use of gitweb.cgi in FastCGI mode reliably with a greater variety of web server software than would otherwise be possible. The new script, "gitweb-gc.sh" gets installed in the "$Girocco::Config::basedir/bin" directory after performing an install of Girocco. When configuring a web server that does not properly handle FastCGI "zero status [...] crude form of garbage collection" exits, instead of configuring it to execute "$Gircco::Config::cgiroot/gitweb.cgi" directly, it must be configured to execute "$Girocco::Config::basedir/bin/gitweb-gc.sh" instead. This will allow the deficient web server software to provide gitweb services via FastCGI (much, much, much, much more responsive than spawning a new gitweb instance for each request) while avoiding sporadic intermittent failures as gitweb exits after serving 100 requests to perform a "crude form of garbage collection." Signed-off-by: Kyle J. McKay <mackyle@gmail.com> --- bin/gitweb-gc.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 bin/gitweb-gc.sh diff --git a/bin/gitweb-gc.sh b/bin/gitweb-gc.sh new file mode 100755 index 0000000..d869ecf --- /dev/null +++ b/bin/gitweb-gc.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Allow gitweb.cgi to be run from a fastcgi server that does +# not really support periodic "garbage collection" exits +# (even on an exit status of 0) without losing fastcgi requests. +# Signals are forwarded in both directions. +cgiroot=@cgiroot@ +bg= +handle_sig() { [ -z "$bg" ] || kill -$1 "$bg" 2>/dev/null; } +# backgrounding the cgi with '&' causes it to ignore SIGINT and SIGQUIT +# therefore we redirect INT to TERM and QUIT to ABRT when forwarding those +trap 'handle_sig HUP' HUP +trap 'handle_sig ABRT' ABRT QUIT +trap 'handle_sig PIPE' PIPE +trap 'handle_sig ALRM' ALRM +trap 'handle_sig TERM' TERM INT +trap 'handle_sig USR1' USR1 +trap 'handle_sig USR2' USR2 +while :; do + exec 3<&0 + (exec 0<&3 3<&-; exec "$cgiroot/gitweb.cgi" "$@")& + bg="$!" + exec 3<&- + while :; do + ec=0 + wait "$bg" || ec="$?" + kill -0 "$bg" 2>/dev/null || break + # was a signal to self that's now been forwarded + # go around the loop again + done + bg= + [ "${ec:-0}" = "0" ] || break + # was a gitweb "garbage collection" exit + # go around the loop again and restart gitweb +done +trap - HUP INT QUIT ABRT PIPE ALRM TERM USR1 USR2 +if [ "${ec:-0}" -gt 128 ] && [ "${ec:-0}" -lt 160 ]; then + # self terminate + kill -$(($ec-128)) $$ +fi +exit "$ec" -- 2.11.4.GIT