diff options
author | Junio C Hamano <gitster@pobox.com> | 2010-02-02 21:48:22 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-02-02 21:48:22 -0800 |
commit | 484e669aa772a3f6386d0f03f7c75af603801813 (patch) | |
tree | ba785eb29d1657e192601e5a6761acaf54da7973 | |
parent | 347d04d0e2a0f5813a80eed7ce2b38debaf5ce00 (diff) | |
parent | aa14013abf27637dc2a2c0bee56fb98a981ee08d (diff) | |
download | git-484e669aa772a3f6386d0f03f7c75af603801813.tar.gz |
Merge branch 'jh/gitweb-caching' (early part)
* 'jh/gitweb-caching' (early part):
gitweb: Add optional extra parameter to die_error, for extended explanation
gitweb: add a "string" variant of print_sort_th
gitweb: add a "string" variant of print_local_time
gitweb: Check that $site_header etc. are defined before using them
gitweb: Makefile improvements
gitweb: Load checking
gitweb: Make running t9501 test with '--debug' reliable and usable
-rw-r--r-- | Makefile | 65 | ||||
-rw-r--r-- | gitweb/Makefile | 129 | ||||
-rw-r--r-- | gitweb/README | 7 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 92 | ||||
-rw-r--r-- | t/gitweb-lib.sh | 1 | ||||
-rwxr-xr-x | t/t9501-gitweb-standalone-http-status.sh | 30 |
6 files changed, 248 insertions, 76 deletions
@@ -275,29 +275,6 @@ pathsep = : # JavaScript minifier invocation that can function as filter JSMIN = -# default configuration for gitweb -GITWEB_CONFIG = gitweb_config.perl -GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf -GITWEB_HOME_LINK_STR = projects -GITWEB_SITENAME = -GITWEB_PROJECTROOT = /pub/git -GITWEB_PROJECT_MAXDEPTH = 2007 -GITWEB_EXPORT_OK = -GITWEB_STRICT_EXPORT = -GITWEB_BASE_URL = -GITWEB_LIST = -GITWEB_HOMETEXT = indextext.html -GITWEB_CSS = gitweb.css -GITWEB_LOGO = git-logo.png -GITWEB_FAVICON = git-favicon.png -ifdef JSMIN -GITWEB_JS = gitweb.min.js -else -GITWEB_JS = gitweb.js -endif -GITWEB_SITE_HEADER = -GITWEB_SITE_FOOTER = - export prefix bindir sharedir sysconfdir CC = gcc @@ -1518,6 +1495,11 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl chmod +x $@+ && \ mv $@+ $@ + +.PHONY: gitweb +gitweb: + $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all + ifdef JSMIN OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.min.js gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js @@ -1525,30 +1507,13 @@ else OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.cgi: gitweb/gitweb.perl endif - $(QUIET_GEN)$(RM) $@ $@+ && \ - sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ - -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \ - -e 's|++GIT_BINDIR++|$(bindir)|g' \ - -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \ - -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \ - -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \ - -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \ - -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \ - -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \ - -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \ - -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \ - -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \ - -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \ - -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \ - -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \ - -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \ - -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \ - -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \ - -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \ - -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \ - $< >$@+ && \ - chmod +x $@+ && \ - mv $@+ $@ + $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@) + +ifdef JSMIN +gitweb/gitweb.min.js: gitweb/gitweb.js + $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@) +endif # JSMIN + git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js $(QUIET_GEN)$(RM) $@ $@+ && \ @@ -1575,12 +1540,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh mv $@+ $@ endif # NO_PERL - -ifdef JSMIN -gitweb/gitweb.min.js: gitweb/gitweb.js - $(QUIET_GEN)$(JSMIN) <$< >$@ -endif # JSMIN - ifndef NO_PYTHON $(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py diff --git a/gitweb/Makefile b/gitweb/Makefile new file mode 100644 index 0000000000..c9eb1ee667 --- /dev/null +++ b/gitweb/Makefile @@ -0,0 +1,129 @@ +# The default target of this Makefile is... +all:: + +# Define V=1 to have a more verbose compile. +# +# Define JSMIN to point to JavaScript minifier that functions as +# a filter to have gitweb.js minified. +# + +prefix ?= $(HOME) +bindir ?= $(prefix)/bin +RM ?= rm -f + +# JavaScript minifier invocation that can function as filter +JSMIN ?= + +# default configuration for gitweb +GITWEB_CONFIG = gitweb_config.perl +GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf +GITWEB_HOME_LINK_STR = projects +GITWEB_SITENAME = +GITWEB_PROJECTROOT = /pub/git +GITWEB_PROJECT_MAXDEPTH = 2007 +GITWEB_EXPORT_OK = +GITWEB_STRICT_EXPORT = +GITWEB_BASE_URL = +GITWEB_LIST = +GITWEB_HOMETEXT = indextext.html +GITWEB_CSS = gitweb.css +GITWEB_LOGO = git-logo.png +GITWEB_FAVICON = git-favicon.png +ifdef JSMIN +GITWEB_JS = gitweb.min.js +else +GITWEB_JS = gitweb.js +endif +GITWEB_SITE_HEADER = +GITWEB_SITE_FOOTER = + +# include user config +-include ../config.mak.autogen +-include ../config.mak + +# determine version +../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE + $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE + +-include ../GIT-VERSION-FILE + +### Build rules + +SHELL_PATH ?= $(SHELL) +PERL_PATH ?= /usr/bin/perl + +# Shell quote; +bindir_SQ = $(subst ','\'',$(bindir)) #' +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) #' +PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) #' + +# Quiet generation (unless V=1) +QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + QUIET = @ + QUIET_GEN = $(QUIET)echo ' ' GEN $@; + QUIET_SUBDIR0 = +@subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V + export QUIET + export QUIET_GEN + export QUIET_SUBDIR0 + export QUIET_SUBDIR1 +endif +endif + +all:: gitweb.cgi + +ifdef JSMIN +FILES=gitweb.cgi gitweb.min.js +gitweb.cgi: gitweb.perl gitweb.min.js +else # !JSMIN +FILES=gitweb.cgi +gitweb.cgi: gitweb.perl +endif # JSMIN + +gitweb.cgi: + $(QUIET_GEN)$(RM) $@ $@+ && \ + sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ + -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \ + -e 's|++GIT_BINDIR++|$(bindir)|g' \ + -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \ + -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \ + -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \ + -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \ + -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \ + -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \ + -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \ + -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \ + -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \ + -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \ + -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \ + -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \ + -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \ + -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \ + -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \ + -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \ + -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \ + $< >$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ + +ifdef JSMIN +gitweb.min.js: gitweb.js + $(QUIET_GEN)$(JSMIN) <$< >$@ +endif # JSMIN + +clean: + $(RM) $(FILES) + +.PHONY: all clean .FORCE-GIT-VERSION-FILE diff --git a/gitweb/README b/gitweb/README index e34ee793ef..6c2c8e1259 100644 --- a/gitweb/README +++ b/gitweb/README @@ -174,7 +174,7 @@ not include variables usually directly set during build): Base URL for relative URLs in pages generated by gitweb, (e.g. $logo, $favicon, @stylesheets if they are relative URLs), needed and used only for URLs with nonempty PATH_INFO via - <base href="$base_url>. Usually gitweb sets its value correctly, + <base href="$base_url">. Usually gitweb sets its value correctly, and there is no need to set this variable, e.g. to $my_uri or "/". * $home_link Target of the home link on top of all pages (the first part of view @@ -228,6 +228,11 @@ not include variables usually directly set during build): repositories from launching cross-site scripting (XSS) attacks. Set this to true if you don't trust the content of your repositories. The default is false. + * $maxload + Used to set the maximum load that we will still respond to gitweb queries. + If server load exceed this value then return "503 Service Unavaliable" error. + Server load is taken to be 0 if gitweb cannot determine its value. Set it to + undefined value to turn it off. The default is 300. Projects list file format diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7e477af956..d0c3ff258d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -221,6 +221,12 @@ our %avatar_size = ( 'double' => 32 ); +# Used to set the maximum load that we will still respond to gitweb queries. +# If server load exceed this value then return "503 server busy" error. +# If gitweb cannot determined server load, it is taken to be 0. +# Leave it undefined (or set to 'undef') to turn off load checking. +our $maxload = 300; + # You define site-wide feature defaults here; override them with # $GITWEB_CONFIG as necessary. our %feature = ( @@ -551,12 +557,38 @@ if (-e $GITWEB_CONFIG) { do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM; } +# Get loadavg of system, to compare against $maxload. +# Currently it requires '/proc/loadavg' present to get loadavg; +# if it is not present it returns 0, which means no load checking. +sub get_loadavg { + if( -e '/proc/loadavg' ){ + open my $fd, '<', '/proc/loadavg' + or return 0; + my @load = split(/\s+/, scalar <$fd>); + close $fd; + + # The first three columns measure CPU and IO utilization of the last one, + # five, and 10 minute periods. The fourth column shows the number of + # currently running processes and the total number of processes in the m/n + # format. The last column displays the last process ID used. + return $load[0] || 0; + } + # additional checks for load average should go here for things that don't export + # /proc/loadavg + + return 0; +} + # version of the core git binary our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown"; $number_of_git_cmds++; $projects_list ||= $projectroot; +if (defined $maxload && get_loadavg() > $maxload) { + die_error(503, "The load average on the server is too high"); +} + # ====================================================================== # input validation and dispatch @@ -3222,7 +3254,7 @@ EOF print "</head>\n" . "<body>\n"; - if (-f $site_header) { + if (defined $site_header && -f $site_header) { insert_file($site_header); } @@ -3323,12 +3355,13 @@ sub git_footer_html { print "</div>\n"; # class="page_footer" } - if (-f $site_footer) { + if (defined $site_footer && -f $site_footer) { insert_file($site_footer); } print qq!<script type="text/javascript" src="$javascript"></script>\n!; - if ($action eq 'blame_incremental') { + if (defined $action && + $action eq 'blame_incremental') { print qq!<script type="text/javascript">\n!. qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!. qq! "!. href() .qq!");\n!. @@ -3354,22 +3387,33 @@ sub git_footer_html { # 500: The server isn't configured properly, or # an internal error occurred (e.g. failed assertions caused by bugs), or # an unknown error occurred (e.g. the git binary died unexpectedly). +# 503: The server is currently unavailable (because it is overloaded, +# or down for maintenance). Generally, this is a temporary state. sub die_error { my $status = shift || 500; my $error = shift || "Internal server error"; - - my %http_responses = (400 => '400 Bad Request', - 403 => '403 Forbidden', - 404 => '404 Not Found', - 500 => '500 Internal Server Error'); + my $extra = shift; + + my %http_responses = ( + 400 => '400 Bad Request', + 403 => '403 Forbidden', + 404 => '404 Not Found', + 500 => '500 Internal Server Error', + 503 => '503 Service Unavailable', + ); git_header_html($http_responses{$status}); print <<EOF; <div class="page_body"> <br /><br /> $status - $error <br /> -</div> EOF + if (defined $extra) { + print "<hr />\n" . + "$extra\n"; + } + print "</div>\n"; + git_footer_html(); exit; } @@ -3471,14 +3515,21 @@ sub git_print_header_div { } sub print_local_time { + print format_local_time(@_); +} + +sub format_local_time { + my $localtime = ''; my %date = @_; if ($date{'hour_local'} < 6) { - printf(" (<span class=\"atnight\">%02d:%02d</span> %s)", + $localtime .= sprintf(" (<span class=\"atnight\">%02d:%02d</span> %s)", $date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'}); } else { - printf(" (%02d:%02d %s)", + $localtime .= sprintf(" (%02d:%02d %s)", $date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'}); } + + return $localtime; } # Outputs the author name and date in long form @@ -4302,17 +4353,24 @@ sub fill_project_list_info { # print 'sort by' <th> element, generating 'sort by $name' replay link # if that order is not selected sub print_sort_th { + print format_sort_th(@_); +} + +sub format_sort_th { my ($name, $order, $header) = @_; + my $sort_th = ""; $header ||= ucfirst($name); if ($order eq $name) { - print "<th>$header</th>\n"; + $sort_th .= "<th>$header</th>\n"; } else { - print "<th>" . - $cgi->a({-href => href(-replay=>1, order=>$name), - -class => "header"}, $header) . - "</th>\n"; + $sort_th .= "<th>" . + $cgi->a({-href => href(-replay=>1, order=>$name), + -class => "header"}, $header) . + "</th>\n"; } + + return $sort_th; } sub git_project_list_body { @@ -4743,7 +4801,7 @@ sub git_project_list { } git_header_html(); - if (-f $home_text) { + if (defined $home_text && -f $home_text) { print "<div class=\"index_include\">\n"; insert_file($home_text); print "</div>\n"; diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh index 76d8b7b803..5a734b1b7b 100644 --- a/t/gitweb-lib.sh +++ b/t/gitweb-lib.sh @@ -25,6 +25,7 @@ our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png'; our \$projects_list = ''; our \$export_ok = ''; our \$strict_export = ''; +our \$maxload = undef; EOF diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index 0688a57e1d..7590f10b66 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -33,7 +33,6 @@ test_expect_success \ grep "403 - Snapshot format not allowed" gitweb.output && gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" && grep "403 - Unsupported snapshot format" gitweb.output' -test_debug 'cat gitweb.output' cat >>gitweb_config.perl <<\EOF @@ -50,7 +49,6 @@ test_expect_success \ grep "403 - Snapshot format not allowed" gitweb.output && gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" && grep "Status: 200 OK" gitweb.output' -test_debug 'cat gitweb.output' cat >>gitweb_config.perl <<\EOF @@ -72,7 +70,7 @@ test_expect_success \ 'snapshots: tgz explicitly enabled' \ 'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" && grep "Status: 200 OK" gitweb.output' -test_debug 'cat gitweb.output' +test_debug 'cat gitweb.headers' # ---------------------------------------------------------------------- @@ -82,7 +80,7 @@ test_expect_success 'snapshots: good tree-ish id' ' gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && grep "Status: 200 OK" gitweb.output ' -test_debug 'cat gitweb.output' +test_debug 'cat gitweb.headers' test_expect_success 'snapshots: bad tree-ish id' ' gitweb_run "p=.git;a=snapshot;h=frizzumFrazzum;sf=tgz" && @@ -105,7 +103,7 @@ test_expect_success 'snapshots: good object id' ' gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" && grep "Status: 200 OK" gitweb.output ' -test_debug 'cat gitweb.output' +test_debug 'cat gitweb.headers' test_expect_success 'snapshots: bad object id' ' gitweb_run "p=.git;a=snapshot;h=abcdef01234;sf=tgz" && @@ -114,4 +112,26 @@ test_expect_success 'snapshots: bad object id' ' test_debug 'cat gitweb.output' +# ---------------------------------------------------------------------- +# load checking + +# always hit the load limit +cat >>gitweb_config.perl <<\EOF +our $maxload = 0; +EOF + +test_expect_success 'load checking: load too high (default action)' ' + gitweb_run "p=.git" && + grep "Status: 503 Service Unavailable" gitweb.headers && + grep "503 - The load average on the server is too high" gitweb.body +' +test_debug 'cat gitweb.log' # just in case +test_debug 'cat gitweb.headers' + +# turn off load checking +cat >>gitweb_config.perl <<\EOF +our $maxload = undef; +EOF + + test_done |