From: (no author) <(no author)@unknown>
Date: Tue, 16 Oct 2001 21:29:08 +0000 (+0000)
Subject: This commit was manufactured by cvs2svn to create branch 'avendor'.
X-Git-Tag: HTTPD_LDAP_1_0_0~1
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=517bf7127f1807ffeafea29bf3bafc33f1471acd;p=thirdparty%2Fapache%2Fhttpd.git
This commit was manufactured by cvs2svn to create branch 'avendor'.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/avendor@91505 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/build/.cvsignore b/build/.cvsignore
new file mode 100644
index 00000000000..29d51bb51c6
--- /dev/null
+++ b/build/.cvsignore
@@ -0,0 +1 @@
+rules.mk
diff --git a/build/make_exports.awk b/build/make_exports.awk
new file mode 100644
index 00000000000..27fd631eb9e
--- /dev/null
+++ b/build/make_exports.awk
@@ -0,0 +1,120 @@
+
+BEGIN {
+ printf("/*\n")
+ printf(" * THIS FILE WAS AUTOGENERATED BY make_exports.awk\n")
+ printf(" *\n")
+ printf(" * This is an ugly hack that needs to be here, so\n")
+ printf(" * that libtool will link all of the APR functions\n")
+ printf(" * into server regardless of whether the base server\n")
+ printf(" * uses them.\n")
+ printf(" */\n")
+ printf("\n")
+ printf("#define CORE_PRIVATE\n")
+ printf("\n")
+
+ for (i = 1; i < ARGC; i++) {
+ file = ARGV[i]
+ sub("([^/]*[/])*", "", file)
+ printf("#include \"%s\"\n", file)
+ }
+
+ printf("\n")
+ printf("const void *ap_ugly_hack = NULL;\n")
+ printf("\n")
+
+ TYPE_NORMAL = 0
+ TYPE_HEADER = 1
+
+ stackptr = 0
+}
+
+function push(line) {
+ stack[stackptr] = line
+ stackptr++
+}
+
+function do_output() {
+ printf("/*\n")
+ printf(" * %s\n", FILENAME)
+ printf(" */\n")
+
+ for (i = 0; i < stackptr; i++) {
+ printf("%s\n", stack[i])
+ }
+
+ stackptr = 0
+
+ printf("\n");
+}
+
+function enter_scope(type) {
+ scope++
+ scope_type[scope] = type
+ scope_stack[scope] = stackptr
+ delete scope_used[scope]
+}
+
+function leave_scope() {
+ used = scope_used[scope]
+
+ if (!used)
+ stackptr = scope_stack[scope]
+
+ scope--
+ if (used) {
+ scope_used[scope] = 1
+
+ if (!scope)
+ do_output()
+ }
+}
+
+function add_symbol(symbol) {
+ idx = index(symbol, "#")
+
+ if (!idx) {
+ push("const void *ap_hack_" symbol " = (const void *)" symbol ";")
+ scope_used[scope] = 1
+ }
+}
+
+/^[ \t]*AP[RU]?_DECLARE[^(]*[(][^)]*[)]([^ ]* )*[^(]+[(]/ {
+ sub("[ \t]*AP[RU]?_DECLARE[^(]*[(][^)]*[)]", "");
+ sub("[(].*", "");
+ sub("^[ \t]+", "");
+ sub("([^ ]* ^([ \t]*[(]))*", "");
+
+ add_symbol($0)
+ next
+}
+
+/^#[ \t]*if(ndef| !defined[(])([^_]*_)*H/ {
+ enter_scope(TYPE_HEADER)
+ next
+}
+
+/^#[ \t]*if([n]?def)? / {
+ enter_scope(TYPE_NORMAL)
+ push($0)
+ next
+}
+
+/^#[ \t]*endif/ {
+ if (scope_type[scope] == TYPE_NORMAL)
+ push($0)
+
+ leave_scope()
+ next
+}
+
+/^#[ \t]*else/ {
+ push($0)
+ next
+}
+
+/^#[ \t]*elif/ {
+ push($0)
+ next
+}
+
+
diff --git a/build/make_var_export.awk b/build/make_var_export.awk
new file mode 100644
index 00000000000..62263f10e68
--- /dev/null
+++ b/build/make_var_export.awk
@@ -0,0 +1,59 @@
+# Based on apr's make_export.awk, which is
+# based on Ryan Bloom's make_export.pl
+
+/^#[ \t]*if(def)? (AP[RU]?_|!?defined).*/ {
+ if (old_filename != FILENAME) {
+ if (old_filename != "") printf("%s", line)
+ macro_no = 0
+ found = 0
+ count = 0
+ old_filename = FILENAME
+ line = ""
+ }
+ macro_stack[macro_no++] = macro
+ macro = substr($0, length($1)+2)
+ count++
+ line = line "#ifdef " macro "\n"
+ next
+}
+
+/^#[ \t]*endif/ {
+ if (count > 0) {
+ count--
+ line = line "#endif " macro "\n"
+ macro = macro_stack[--macro_no]
+ }
+ if (count == 0) {
+ if (found != 0) {
+ printf("%s", line)
+ }
+ line = ""
+ }
+ next
+}
+
+function add_symbol (sym_name) {
+ if (count) {
+ found++
+ }
+ for (i = 0; i < count; i++) {
+ line = line "\t"
+ }
+ line = line sym_name "\n"
+
+ if (count == 0) {
+ printf("%s", line)
+ line = ""
+ }
+}
+
+/^[ \t]*AP[RU]?_DECLARE_DATA .*;$/ {
+ varname = $NF;
+ gsub( /[*;]/, "", varname);
+ gsub( /\[.*\]/, "", varname);
+ add_symbol(varname);
+}
+
+END {
+ printf("%s", line)
+}
diff --git a/build/rules.mk.in b/build/rules.mk.in
new file mode 100644
index 00000000000..659cbcf877f
--- /dev/null
+++ b/build/rules.mk.in
@@ -0,0 +1,264 @@
+# ====================================================================
+# The Apache Software License, Version 1.1
+#
+# Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+# reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# 3. The end-user documentation included with the redistribution,
+# if any, must include the following acknowledgment:
+# "This product includes software developed by the
+# Apache Software Foundation (http://www.apache.org/)."
+# Alternately, this acknowledgment may appear in the software itself,
+# if and wherever such third-party acknowledgments normally appear.
+#
+# 4. The names "Apache" and "Apache Software Foundation" must
+# not be used to endorse or promote products derived from this
+# software without prior written permission. For written
+# permission, please contact apache@apache.org.
+#
+# 5. Products derived from this software may not be called "Apache",
+# nor may "Apache" appear in their name, without prior written
+# permission of the Apache Software Foundation.
+#
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+# ====================================================================
+#
+# This software consists of voluntary contributions made by many
+# individuals on behalf of the Apache Software Foundation. For more
+# information on the Apache Software Foundation, please see
+# .
+#
+# The build environment was originally provided by Sascha Schumann.
+#
+
+include $(top_builddir)/config_vars.mk
+
+# Combine all of the flags together in the proper order so that
+# the user-defined flags can always override the configure ones, if needed.
+# Note that includes are listed after the flags because -I options have
+# left-to-right precedence and CPPFLAGS may include user-defined overrides.
+#
+ALL_CFLAGS = $(EXTRA_CFLAGS) $(NOTEST_CFLAGS) $(CFLAGS)
+ALL_CPPFLAGS = $(DEFS) $(EXTRA_CPPFLAGS) $(NOTEST_CPPFLAGS) $(CPPFLAGS)
+ALL_CXXFLAGS = $(EXTRA_CXXFLAGS) $(NOTEST_CXXFLAGS) $(CXXFLAGS)
+ALL_LDFLAGS = $(EXTRA_LDFLAGS) $(NOTEST_LDFLAGS) $(LDFLAGS)
+ALL_LIBS = $(EXTRA_LIBS) $(NOTEST_LIBS) $(LIBS)
+ALL_INCLUDES = $(INCLUDES) $(EXTRA_INCLUDES)
+
+# Compile commands
+
+COMPILE = $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(ALL_INCLUDES)
+CXX_COMPILE = $(CXX) $(ALL_CXXFLAGS) $(ALL_CPPFLAGS) $(ALL_INCLUDES)
+
+SH_COMPILE = $(LIBTOOL) --mode=compile $(COMPILE) @SHLTCFLAGS@ -c $< && touch $@
+SH_CXX_COMPILE = $(LIBTOOL) --mode=compile $(CXX_COMPILE) @SHLTCFLAGS@ -c $< && touch $@
+
+LT_COMPILE = $(LIBTOOL) --mode=compile $(COMPILE) @LTCFLAGS@ -c $< && touch $@
+LT_CXX_COMPILE = $(LIBTOOL) --mode=compile $(CXX_COMPILE) @LTCFLAGS@ -c $< && touch $@
+
+# Link-related commands
+
+LINK = $(LIBTOOL) --mode=link $(COMPILE) $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@
+SH_LINK = $(SH_LIBTOOL) --mode=link $(COMPILE) $(LT_LDFLAGS) $(ALL_LDFLAGS) $(SH_LDFLAGS) $(CORE_IMPLIB) -o $@
+MOD_LINK = $(LIBTOOL) --mode=link $(COMPILE) -module $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@
+
+# Cross compile commands
+
+# Helper programs
+
+MKINSTALLDIRS = $(abs_srcdir)/build/mkdir.sh
+INSTALL = $(abs_srcdir)/build/install.sh -c
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_PROGRAM = $(INSTALL) -m 755 $(INSTALL_PROG_FLAGS)
+
+#
+# Standard build rules
+#
+all: all-recursive
+depend: depend-recursive
+clean: clean-recursive
+distclean: distclean-recursive
+extraclean: extraclean-recursive
+install: install-recursive
+shared-build: shared-build-recursive
+
+all-recursive install-recursive depend-recursive:
+ @otarget=`echo $@|sed s/-recursive//`; \
+ list='$(SUBDIRS)'; \
+ for i in $$list; do \
+ if test -d "$$i"; then \
+ target="$$otarget"; \
+ echo "Making $$target in $$i"; \
+ if test "$$i" = "."; then \
+ made_local=yes; \
+ target="local-$$target"; \
+ fi; \
+ (cd $$i && $(MAKE) $$target) || exit 1; \
+ fi; \
+ done; \
+ if test "$$otarget" = "all" && test -z '$(TARGETS)'; then \
+ made_local=yes; \
+ fi; \
+ if test "$$made_local" != "yes"; then \
+ $(MAKE) "local-$$otarget" || exit 1; \
+ fi
+
+clean-recursive distclean-recursive extraclean-recursive:
+ @otarget=`echo $@|sed s/-recursive//`; \
+ list='$(SUBDIRS) $(CLEAN_SUBDIRS)'; \
+ for i in $$list; do \
+ if test -d "$$i"; then \
+ target="$$otarget"; \
+ echo "Making $$target in $$i"; \
+ if test "$$i" = "."; then \
+ made_local=yes; \
+ target="local-$$target"; \
+ fi; \
+ (cd $$i && $(MAKE) $$target); \
+ fi; \
+ done; \
+ if test "$$otarget" = "all" && test -z '$(TARGETS)'; then \
+ made_local=yes; \
+ fi; \
+ if test "$$made_local" != "yes"; then \
+ $(MAKE) "local-$$otarget"; \
+ fi
+
+shared-build-recursive:
+ @if test `pwd` = "$(top_builddir)"; then \
+ $(PRE_SHARED_CMDS) ; \
+ fi; \
+ list='$(SUBDIRS)'; for i in $$list; do \
+ target="shared-build"; \
+ if test "$$i" = "."; then \
+ made_local=yes; \
+ target="local-shared-build"; \
+ fi; \
+ if test "$$i" != "srclib"; then \
+ (cd $$i && $(MAKE) $$target) || exit 1; \
+ fi; \
+ done; \
+ if test -f 'modules.mk'; then \
+ if test -n '$(SHARED_TARGETS)'; then \
+ echo "Building shared: $(SHARED_TARGETS)"; \
+ if test "$$made_local" != "yes"; then \
+ $(MAKE) "local-shared-build" || exit 1; \
+ fi; \
+ fi; \
+ fi; \
+ if test `pwd` = "$(top_builddir)"; then \
+ $(POST_SHARED_CMDS) ; \
+ fi
+
+local-all: $(TARGETS)
+
+local-shared-build: $(SHARED_TARGETS)
+
+local-depend: x-local-depend
+ if test "`echo $(srcdir)/*.c`" != "$(srcdir)'/*.c'"; then \
+ $(CC) -MM $(ALL_CPPFLAGS) $(ALL_INCLUDES) $(srcdir)/*.c | sed 's/\.o:/.lo:/' > $(builddir)/.deps || true; \
+ fi
+
+local-clean: x-local-clean
+ rm -f *.o *.lo *.slo *.obj *.a *.la $(CLEAN_TARGETS) $(TARGETS)
+ rm -rf .libs
+
+local-distclean: local-clean x-local-distclean
+ rm -f .deps Makefile $(DISTCLEAN_TARGETS)
+
+local-extraclean: local-distclean x-local-extraclean
+ @if test -n "$(EXTRACLEAN_TARGETS)"; then \
+ echo "rm -f $(EXTRACLEAN_TARGETS)"; \
+ rm -f $(EXTRACLEAN_TARGETS) ; \
+ fi
+
+local-install: $(TARGETS) $(SHARED_TARGETS) $(INSTALL_TARGETS)
+ @if test -n '$(PROGRAMS)'; then \
+ test -d $(bindir) || $(MKINSTALLDIRS) $(bindir); \
+ list='$(PROGRAMS)'; for i in $$list; do \
+ $(INSTALL_PROGRAM) $$i $(bindir); \
+ done; \
+ fi
+
+# to be filled in by the actual Makefile if extra commands are needed
+x-local-depend x-local-clean x-local-distclean x-local-extraclean:
+
+#
+# Implicit rules for creating outputs from input files
+#
+CXX_SUFFIX = cpp
+SHLIB_SUFFIX = so
+
+.SUFFIXES:
+.SUFFIXES: .S .c .$(CXX_SUFFIX) .lo .o .s .y .l .slo .def .la
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.c.lo:
+ $(LT_COMPILE)
+
+.s.lo:
+ $(LT_COMPILE)
+
+.c.slo:
+ $(SH_COMPILE)
+
+.$(CXX_SUFFIX).lo:
+ $(LT_CXX_COMPILE)
+
+.$(CXX_SUFFIX).slo:
+ $(SH_CXX_COMPILE)
+
+.y.c:
+ $(YACC) $(YFLAGS) $< && mv y.tab.c $*.c
+ if test -f y.tab.h; then \
+ if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+ else :; fi
+
+.l.c:
+ $(LEX) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
+
+# Makes an import library from a def file
+.def.la:
+ $(LIBTOOL) --mode=compile $(MK_IMPLIB) -o $@ $<
+
+#
+# Dependencies
+#
+include $(builddir)/.deps
+
+.PHONY: all all-recursive install-recursive local-all $(PHONY_TARGETS) \
+ shared-build shared-build-recursive local-shared-build \
+ depend depend-recursive local-depend x-local-depend \
+ clean clean-recursive local-clean x-local-clean \
+ distclean distclean-recursive local-distclean x-local-distclean \
+ extraclean extraclean-recursive local-extraclean x-local-extraclean \
+ install local-install $(INSTALL_TARGETS)
+
diff --git a/build/win32/.cvsignore b/build/win32/.cvsignore
new file mode 100644
index 00000000000..3a755604911
--- /dev/null
+++ b/build/win32/.cvsignore
@@ -0,0 +1,2 @@
+Apache.aps
+Apache.rc
diff --git a/build/win32/apache.ico b/build/win32/apache.ico
new file mode 100644
index 00000000000..5e8adcbfc5d
Binary files /dev/null and b/build/win32/apache.ico differ
diff --git a/build/win32/win32ver.awk b/build/win32/win32ver.awk
new file mode 100644
index 00000000000..8862aa87f34
--- /dev/null
+++ b/build/win32/win32ver.awk
@@ -0,0 +1,108 @@
+BEGIN {
+
+ # ff bits: 1(debug), 2(prerelease), 4(patched), 8(vendor) and 32(special)
+ # debug is summed based on the /Define _DEBUG
+ # prerelease is based on the -dev extension,
+ # patched is based on a non-standard "-ver" extension,
+ # special and vendor are toggled by their args.
+ #
+ ff = 0;
+
+ file=ARGV[1];
+ desc=ARGV[2];
+ rel_h=ARGV[3];
+
+ i = 4;
+ while (length(ARGV[i])) {
+ if (match(ARGV[i], /icon=/)) {
+ icon = substr(ARGV[i], 6);
+ }
+ if (match(ARGV[i], /vendor=/)) {
+ vendor = substr(ARGV[i], 8);
+ ff = ff + 8;
+ }
+ if (match(ARGV[i], /special=/)) {
+ special = substr(ARGV[i], 9);
+ ff = ff + 32;
+ }
+ i = i + 1
+ }
+
+ i = i - 1;
+ while (i) {
+ delete ARGV[i];
+ i = i - 1;
+ }
+
+ while ((getline < rel_h) > 0) {
+ if (match ($0, /^#define AP_SERVER_BASEREVISION "[^"]+"/)) {
+ ver = substr($0, RSTART + 32, RLENGTH - 33);
+ }
+ }
+
+ verc = ver;
+ gsub(/\./, ",", verc);
+ if (build) {
+ sub(/-.*/, "", verc)
+ verc = verc "," build;
+ } else if (sub(/-dev/, ",0", verc)) {
+ ff = ff + 2;
+ } else if (!sub(/-alpha/, ",10", verc) \
+ && !sub(/-beta/, ",100", verc) \
+ && !sub(/-gold/, ",200", verc)) {
+ sub(/-.*/, "", verc);
+ verc = verc "," 0;
+ }
+
+ if (length(vendor)) {
+ ff = ff + 8;
+ }
+
+ if (length(icon)) {
+ print "1 ICON DISCARDABLE \"" icon "\"";
+ }
+ print "1 VERSIONINFO";
+ print " FILEVERSION " verc "";
+ print " PRODUCTVERSION " verc "";
+ print " FILEFLAGSMASK 0x3fL";
+ print "#if defined(_DEBUG)"
+ print " FILEFLAGS 0x" sprintf("%02x", ff + 1) "L";
+ print "#else"
+ print " FILEFLAGS 0x" sprintf("%02x", ff) "L";
+ print "#endif"
+ print " FILEOS 0x40004L";
+ print " FILETYPE 0x1L";
+ print " FILESUBTYPE 0x0L";
+ print "BEGIN";
+ print " BLOCK \"StringFileInfo\"";
+ print " BEGIN";
+ print " BLOCK \"00000000\"";
+ print " BEGIN";
+ print " VALUE \"Comments\", \"This software consists of " \
+ "voluntary contributions made by many individuals on behalf of " \
+ "the Apache Software Foundation. For more information on the " \
+ "Apache Software Foundation, please see \\0\"";
+ print " VALUE \"CompanyName\", \"Apache Software Foundation.\\0\"";
+ print " VALUE \"FileDescription\", \"" desc "\\0\"";
+ print " VALUE \"FileVersion\", \"" ver "\\0\"";
+ print " VALUE \"InternalName\", \"" file "\\0\"";
+ print " VALUE \"LegalCopyright\", \"Copyright (c) 2001, " \
+ "The Apache Software Foundation. Current License is available from " \
+ "\\0\"";
+ print " VALUE \"OriginalFilename\", \"" file ".exe\\0\"";
+ if (vendor) {
+ print " VALUE \"PrivateBuild\", \"" vendor "\\0\"";
+ }
+ if (special) {
+ print " VALUE \"SpecialBuild\", \"" vendor "\\0\"";
+ }
+ print " VALUE \"ProductName\", \"Apache httpd Server\\0\"";
+ print " VALUE \"ProductVersion\", \"" ver "\\0\"";
+ print " END";
+ print " END";
+ print " BLOCK \"VarFileInfo\"";
+ print " BEGIN";
+ print " VALUE \"Translation\", 0, 1200";
+ print " END";
+ print "END";
+}
\ No newline at end of file
diff --git a/docs/docroot/apache_pb.png b/docs/docroot/apache_pb.png
new file mode 100644
index 00000000000..eb99a8cd393
Binary files /dev/null and b/docs/docroot/apache_pb.png differ
diff --git a/docs/docroot/apache_pb2.png b/docs/docroot/apache_pb2.png
new file mode 100644
index 00000000000..28baa70fb8c
Binary files /dev/null and b/docs/docroot/apache_pb2.png differ
diff --git a/docs/docroot/index.html.cz.iso8859-2 b/docs/docroot/index.html.cz.iso8859-2
new file mode 100644
index 00000000000..e0cd2ba6109
--- /dev/null
+++ b/docs/docroot/index.html.cz.iso8859-2
@@ -0,0 +1,51 @@
+
+
+
+
+ Testovací stránka instalace web serveru Apache
+
+
+
+
+ Funguje to! Na tomto serveru bì¾í Apache!
+
+
+ Pokud vidíte tuto zprávu, správce tohoto poèítaèe právì úspì¹nì
+ nainstaloval Apache web server.
+ Teï je¹tì musí doplnit obsah a nahradit tuto standardní uvítací
+ stránku, nebo pøesmìrovat server na skuteènou domovskou stránku.
+
+
+
+ Pokud vidíte tuto zprávu místo oèekávané domovské stránky,
+ kontaktujte, prosím, správce pøíslu¹ného web
+ serveru. (Zkuste poslat e-mail na adresu
+ <Webmaster@domain>.)
+ Pøesto¾e tento server pou¾ívá program Apache, témìø jistì nemá nic
+ spoleèného s Apache Group, proto prosím neposílejte e-maily o tomto
+ serveru nebo jeho obsahu autorùm Apache. Pokud to udìláte, budeme
+ va¹e zprávy ignorovat.
+
+
+
+ Zde najdete
+ dokumentaci
+ Apache (anglicky) obsa¾enou v této distribuci.
+
+
+ Následující logo mù¾e být pou¾ito bez omezení na web serveru s
+ programem Apache. Dìkujeme za pou¾ití Apache!
+
Ukoliko vidite ovu stranicu, to znaèi da je instalacija Apache web poslu¾itelja uspje¹no izvr¹ena na ovom raèunalu.
+Sada mo¾ete dodati sadr¾aj u ovaj direktorij te promijeniti ovu stranicu.
+
+
+
Oèekivali ste neku drugu stranicu?
+
+
Ovu stranica vidite stoga ¹to je administrator ovog poslu¾itelja promijenio
+konfiguraciju. Apache Softver Fondacija napisala je softver koji koristi
+administrator ovog web poslu¾itelja i nije odgovorna za odr¾avanje ovog poslu¾itelja. Molimo vas da za sva pitanja kontaktirate odgovornu
+osobu za odr¾avanje ovog poslu¾itelja.
+
+
+
Ovdje se nalazi Dokumentacija o Apache web poslu¾itelju
+(engleski).
+
+
Donju slièicu mo¾ete slobodno koristiti na stranicama ovog veb poslu¾itelja.
+Hvala vam ¹to koristite Apache!
+ Det gjekk bra! Apache er no installert på denne maskina!
+
+
+ Dersom du kan sjå denne sida, har den eller dei som driv denne nettstaden
+ installert Apache vevtenar.
+ No må denne testsida erstattast med verkeleg innhald.
+
+
+
+ Dersom du hadde venta å sjå ei anna side enn denne, bør du
+ ta kontakt med den som er ansvarleg for denne nettstaden
+ (Prøv å sende e-post til <webmaster@domene>.)
+ Sjølv om denne nettstaden vert kjørt på Apache, har den ingen annan
+ tilknytning til Apache-gruppa, som har utvikla programvaren.
+ Ver snill og ikkje send e-post om denne nettstaden eller
+ innhaldet du finn her til utviklarane i Apache-gruppa.
+ I så tilfelle vil førespurnaden ignorerast.
+
+
+
+ Dokumentasjon
+ for Apache er inkludert i denne pakka.
+
+
+ Logoen under kan brukast på kva som helst av maskiner som køyrer Apache.
+ Takk for at du nyttar Apache!
+
+Je¿eli strona ta jest widoczna, oznacza to poprawn± instalacjê serwera Apache. Mo¿na ju¿ zamieniæ zawarto¶æ tej witryny.
+
+
+
+
Czy zamiast spodziewanej witryny WWW widoczna jest ta?
+
+
+Strona ta jest widoczna, poniewa¿ administrator serwera WWW zmieni³ jego konfiguracjê.
+Proszê skontaktowaæ siê z osob± odpowiedzialn± za zarz±dzanie tym serwerem. Apache Software Foundation, producent oprogramowania serwerowego Apache, nie administruje t± witryn± i nie jest w stanie pomóc w sprawach zwi±zanych z jej konfiguracj±.
+
+
+Poni¿sze logo, "Powered by Apache", mo¿na stosowaæ bez ograniczeñ. Dziêkujemy za wybranie Apache'a!
+
+
+
+
diff --git a/docs/docroot/index.html.var b/docs/docroot/index.html.var
new file mode 100644
index 00000000000..12693fff15d
--- /dev/null
+++ b/docs/docroot/index.html.var
@@ -0,0 +1,34 @@
+index.html.ca
+index.html.cz
+index.html.de
+index.html.dk
+index.html.ee
+index.html.el
+index.html.en
+index.html.es
+index.html.et
+index.html.fr
+index.html.he.iso8859-8
+index.html.it
+index.html.ja.iso2022-jp
+index.html.ja.jis
+index.html.kr.iso-kr
+index.html.kr.iso2022-kr
+index.html.ltz
+index.html.lu
+index.html.nl
+index.html.no
+index.html.po.iso-pl
+index.html.pt
+index.html.pt-br
+index.html.ru.cp-1251
+index.html.ru.cp866
+index.html.ru.iso-ru
+index.html.ru.koi8-r
+index.html.ru.ucs2
+index.html.ru.ucs4
+index.html.ru.utf8
+index.html.se
+index.html.tw
+index.html.tw.Big5
+index.html.var
diff --git a/docs/error/HTTP_BAD_GATEWAY.html.var b/docs/error/HTTP_BAD_GATEWAY.html.var
new file mode 100644
index 00000000000..c6f81de0a1c
--- /dev/null
+++ b/docs/error/HTTP_BAD_GATEWAY.html.var
@@ -0,0 +1,66 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der Proxy-Server erhielt eine fehlerhafte Antwort
+ eines übergeordneten Servers oder Proxies.
+
+
+
+
+
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The proxy server received an invalid
+ response from an upstream server.
+
+
+
+
+
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El servidor fuente recibio información
+ inválida por parte del servidor destino.
+
+
+
+
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Le serveur proxy a reçu une réponse incorrecte de la part d'un serveur supérieur.
+
+
+
+
+
+
+
+----------fr--
diff --git a/docs/error/HTTP_BAD_REQUEST.html.var b/docs/error/HTTP_BAD_REQUEST.html.var
new file mode 100644
index 00000000000..938db8174d2
--- /dev/null
+++ b/docs/error/HTTP_BAD_REQUEST.html.var
@@ -0,0 +1,46 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Ihr Browser (oder Proxy) hat eine ungültige Anfrage gesendet,
+ die vom Server nicht beantwortet werden kann.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ Your browser (or proxy) sent a request that
+ this server could not understand.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El buscador ha solicitado una operación
+ que no puede ser procesada por el servidor.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Votre navigateur (ou votre proxy) a envoyé une demande que ce serveur n'a pas comprise.
+
+
+----------fr--
diff --git a/docs/error/HTTP_FORBIDDEN.html.var b/docs/error/HTTP_FORBIDDEN.html.var
new file mode 100644
index 00000000000..9a30ceb9f19
--- /dev/null
+++ b/docs/error/HTTP_FORBIDDEN.html.var
@@ -0,0 +1,84 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+
+
+ Der Zugriff auf das angeforderte Verzeichnis ist nicht möglich.
+ Entweder ist kein Index-Dokument vorhanden oder das Verzeichnis
+ ist zugriffsgeschützt.
+
+
+
+ Der Zugriff auf das angeforderte Objekt ist nicht möglich.
+ Entweder kann es vom Server nicht gelesen werden oder es
+ ist zugriffsgeschützt.
+
+
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+
+ You don't have permission to access the requested directory.
+ There is either no index document or the directory is read-protected.
+
+
+
+ You don't have permission to access the requested object.
+ It is either read-protected or not readable by the server.
+
+
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+
+
+ Usted no tiene permiso para accesar a la dirección
+ solicitada. Existe la posibilidad de que el directorio
+ este protegido contra lectura o que no exista la
+ documentación requerida.
+
+
+
+ Usted no tiene permiso de accesar al objeto solicitado.
+ Existe la posibilidad de que este protegido contra
+ lectura o que no haya podido ser leido por el servidor.
+
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+Vous n'avez pas le droit d'accéder au répertoire
+demandé. Soit il n'y a pas de document index soit le répertoire
+est protégé.
+
+Vous n'avez pas le droit d'accéder à l'objet
+demandé. Soit celui-ci est protégé, soit il ne peut
+être lu par le serveur.
+
+
+
+----------fr--
diff --git a/docs/error/HTTP_GONE.html.var b/docs/error/HTTP_GONE.html.var
new file mode 100644
index 00000000000..22aef7c674e
--- /dev/null
+++ b/docs/error/HTTP_GONE.html.var
@@ -0,0 +1,100 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der angeforderte URL existiert auf dem Server nicht mehr
+ und wurde dauerhaft entfernt.
+ Eine Weiterleitungsadresse ist nicht verfügbar.
+
+
+
+ Bitte informieren Sie den Autor der
+ ">verweisenden Seite
+ das der Link nicht mehr aktuell ist.
+
+
+
+ Falls Sie einem Link von einer anderen Seite gefolgt sind,
+ informieren Sie bitte den Autor der Seite hierüber.
+
+
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The requested URL is no longer available on this server and there is no
+ forwarding address.
+
+
+
+ Please inform the author of the
+ ">referring
+ page that the link is outdated.
+
+
+
+ If you followed a link from a foreign page, please contact the
+ author of this page.
+
+
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ Los recursos solicitados ya no estan disponibles en
+ este servidor y no existe una dirección alterna.
+
+
+
+ Le solicitamos que comunique al autor de la
+ ">página
+ referida que el URL esta fuera de tiempo.
+
+
+
+ Si usted siguio el URL desde una página externa,
+ porfavor contacte al autor de esa página.
+
+
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ L'URL demandée n'est plus accessible sur ce serveur et il
+ n'y a pas d'adresse de suite.
+
+
+
+ Nous vous prions d'informer l'auteur de
+ ">la
+ page en question que la référence n'est plus actuelle.
+
+
+
+ Si vous avez suivi une référence issue d'une page autre,
+ veuillez contacter l'auteur de cette page.
+
+
+
+----------fr--
diff --git a/docs/error/HTTP_INTERNAL_SERVER_ERROR.html.var b/docs/error/HTTP_INTERNAL_SERVER_ERROR.html.var
new file mode 100644
index 00000000000..742e235eb73
--- /dev/null
+++ b/docs/error/HTTP_INTERNAL_SERVER_ERROR.html.var
@@ -0,0 +1,86 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+
+
+ Dir Proxy-Anfrage konnte nicht ausgeführt werden.
+
+
+
+ Fehlermeldung:
+
+
+
+
+
+ Die Anfrage kann nicht beantwortet werden, da im Server
+ ein interner Fehler aufgetreten ist.
+ Der Server ist entweder überlastet oder ein Fehler in
+ einem CGI-Script ist aufgetreten.
+
+
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+
+
+
+
+ The server encountered an internal error and was
+ unable to complete your request. The server is either
+ overloaded or there was an error in a CGI script.
+
+
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+
+
+
+
+ El servidor encontro un error interno y fue
+ imposible completar su solicitud.
+ Existe tambien la posibilidad de que el servidor
+ este sobrecargado o de algún error en un
+ programa de CGI.
+
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+
+
+
+
+ Le serveur a èté victime d'une erreur interne et n'a pas été
+ capable de faire aboutir votre requête. Soit le server est surchargé
+ soit il s'agit d'une erreur dans le script CGI.
+
+
+
+
+----------fr--
diff --git a/docs/error/HTTP_LENGTH_REQUIRED.html.var b/docs/error/HTTP_LENGTH_REQUIRED.html.var
new file mode 100644
index 00000000000..24d6909c3c4
--- /dev/null
+++ b/docs/error/HTTP_LENGTH_REQUIRED.html.var
@@ -0,0 +1,37 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Die Anfrage kann nicht beantwortet werden.
+ Bei Verwendung der -Methode
+ muß ein korrekter Content-Length-Header
+ angegeben werden.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ A request with the
+ method requires a valid Content-Length header.
+
+
+----------en--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Une requête utilisant la méthode
+ nécessite un header valable Content-Length (indiquant la longueur).
+
+
+----------fr--
diff --git a/docs/error/HTTP_METHOD_NOT_ALLOWED.html.var b/docs/error/HTTP_METHOD_NOT_ALLOWED.html.var
new file mode 100644
index 00000000000..38d2bd8a05c
--- /dev/null
+++ b/docs/error/HTTP_METHOD_NOT_ALLOWED.html.var
@@ -0,0 +1,48 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Die -Methode
+ ist für den angeforderten URL nicht erlaubt.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The
+ method is not allowed for the requested URL.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El
+ método utilizado por su solicitud no esta
+ permitido por el URL.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ La méthode
+ n'est pas utilisable pour l'URL requise.
+
+
+----------fr--
diff --git a/docs/error/HTTP_NOT_ACCEPTABLE.html.var b/docs/error/HTTP_NOT_ACCEPTABLE.html.var
new file mode 100644
index 00000000000..fe4236fac7f
--- /dev/null
+++ b/docs/error/HTTP_NOT_ACCEPTABLE.html.var
@@ -0,0 +1,49 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Unter dem angeforderten URL konnte kein geeignetes Objekt
+ auf dem Server gefunden werden, das dem vom Browser
+ geforderten Format entsprechen würde.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ An appropriate representation of the requested resource
+ could not be found on this server.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ Una representación apropiada de los recursos
+ solicitados no ha podido ser localizada en
+ este servidor.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Une représentation appropriée de la ressource requise
+ n'a pu être trouvée sur ce serveur.
+
+
+----------fr--
diff --git a/docs/error/HTTP_NOT_FOUND.html.var b/docs/error/HTTP_NOT_FOUND.html.var
new file mode 100644
index 00000000000..8a7e8ee5fb8
--- /dev/null
+++ b/docs/error/HTTP_NOT_FOUND.html.var
@@ -0,0 +1,113 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der angeforderte URL konnte auf dem Server nicht gefunden werden.
+
+
+
+ Der Link auf der
+ ">verweisenden
+Seite<
+/a>
+ scheint falsch oder nicht mehr aktuell zu sein.
+ Bitte informieren Sie den Autor
+ ">dieser Seite
+ über den Fehler.
+
+
+
+ Sofern Sie den URL manuell eingegeben haben,
+ überprüfen Sie bitte die Schreibweise und versuchen es erneut.
+
+
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The requested URL was not found on this server.
+
+
+
+ The link on the
+ ">referring
+page
+ seems to be wrong or outdated. Please inform the author of
+ ">that page
+ about the error.
+
+
+
+ If you entered the URL manually please check your
+ spelling and try again.
+
+
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El URL requerido no ha sido localizado en
+ este servidor.
+
+
+
+ El URL en la
+ ">página
+referida
+ parece tener algun error o estar fuera de tiempo. Porfavor
+ comunique al autor de
+ ">la
+página
+ acerca del error.
+
+
+
+ Si usted provisiono el URL de manera manual le solicitamos
+ que porfavor revise los datos e intente de nuevo.
+
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ L'URL requise n'a pu etre trouvée sur ce serveur.
+
+
+
+ La référence sur
+ ">la page
+citée
+ semble être erronée ou perimée. Nous vous prions
+d'informer l'auteur de
+ ">cette page
+ de cette erreur.
+
+
+
+ Si vous avez tapé l'URL à la main, veuillez vérifier
+ l'orthographe et réessayer.
+
+
+
+
+----------fr--
diff --git a/docs/error/HTTP_NOT_IMPLEMENTED.html.var b/docs/error/HTTP_NOT_IMPLEMENTED.html.var
new file mode 100644
index 00000000000..ed3468eaf3b
--- /dev/null
+++ b/docs/error/HTTP_NOT_IMPLEMENTED.html.var
@@ -0,0 +1,45 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Die vom Browser angeforderte Aktion wird vom Server
+ nicht unterstützt.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The server does not support the action requested by the browser.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El buscador esta solicitando una acción
+ que no puede ser procesada.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+Le serveur n'est pas en mesure d'effectuer l'action requise par le navigateur.
+
+
+----------fr--
diff --git a/docs/error/HTTP_PRECONDITION_FAILED.html.var b/docs/error/HTTP_PRECONDITION_FAILED.html.var
new file mode 100644
index 00000000000..164bfcef6d8
--- /dev/null
+++ b/docs/error/HTTP_PRECONDITION_FAILED.html.var
@@ -0,0 +1,44 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Die Vorbedingung unter dem angeforderten URL wurde
+ negativ ausgewertet.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The precondition on the request for the URL failed positive evaluation.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ La precondicion para que exista una
+ conección al URL solicitado es falsa.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+La précondition pour l'URL requise a été évaluée négativement.
+
+----------fr--
diff --git a/docs/error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var b/docs/error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
new file mode 100644
index 00000000000..af7ef260e02
--- /dev/null
+++ b/docs/error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
@@ -0,0 +1,51 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Die bei der Anfrage übermittelnden Daten sind für
+ die -Methode nicht erlaubt
+ oder die Datenmenge hat das Maximum überschritten.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The method does not allow the data
+ transmitted, or the data volume exceeds the capacity limit.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ Los recursos establecidos no permiten peticiones con
+ el método
+ suministrado por su solicitud, o, la cantidad de datos
+ provistos exceden los límites de capacidad.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+La méthode
+n'autorise pas le transfert de ces données ou bien le volume
+des données excède la limite de capacité.
+
+
+----------fr--
diff --git a/docs/error/HTTP_REQUEST_TIME_OUT.html.var b/docs/error/HTTP_REQUEST_TIME_OUT.html.var
new file mode 100644
index 00000000000..6295279a037
--- /dev/null
+++ b/docs/error/HTTP_REQUEST_TIME_OUT.html.var
@@ -0,0 +1,48 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der Server konnte nicht mehr länger auf die Beendigung
+ der Browseranfrage warten, die Netzwerkverbindung wurde
+ vom Server geschlossen.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The server closed the network connection because the browser
+ didn't finish the request within the specified time.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El servidor ha cerrado la conección de red
+ debido a que el buscador no termino la solicitud
+ dentro del tiempo especificado.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+La précondition pour l'URL requise a été évaluée négativement.
+
+
+----------fr--
diff --git a/docs/error/HTTP_REQUEST_URI_TOO_LARGE.html.var b/docs/error/HTTP_REQUEST_URI_TOO_LARGE.html.var
new file mode 100644
index 00000000000..f34de5558c9
--- /dev/null
+++ b/docs/error/HTTP_REQUEST_URI_TOO_LARGE.html.var
@@ -0,0 +1,48 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der bei der Anfrage übermittelnde URI überschreitet
+ die maximale Länge.
+ Die Anfrage kann nicht ausgeführt werden.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The length of the requested URL exceeds the capacity limit for this server.
+ The request cannot be processed.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ Su solicitud no puede procesarse debido a que la
+ longitud del URL excede la capacidad limite del
+ servidor.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+La longueur de l'URL demandée excède la limite de capacitè pour ce serveur. Nous ne pouvons donner suite à votre requête.
+
+
+----------fr--
diff --git a/docs/error/HTTP_SERVICE_UNAVAILABLE.html.var b/docs/error/HTTP_SERVICE_UNAVAILABLE.html.var
new file mode 100644
index 00000000000..d29f16fac8f
--- /dev/null
+++ b/docs/error/HTTP_SERVICE_UNAVAILABLE.html.var
@@ -0,0 +1,56 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der Server ist derzeit nicht in der Lage die Anfrage
+ zu bearbeiten. Entweder ist der Server derzeit überlastet
+ oder wegen Wartungsarbeiten nicht verfügbar.
+ Bitte versuchen Sie es später wieder.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The server is temporarily unable to service your
+ request due to maintenance downtime or capacity
+ problems. Please try again later.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El servidor no puede atender su solicitud por
+ el momento debido a problemas de mantenimiento
+ o de capacidad.
+
+ Le solicitamos que porfavor repita la operación
+ mas tarde.
+
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ En raison de travaux de maintenance ou de problèmes de capacité
+ le serveur n'est pas en mesure de répondre à votre requête pour l'instant.
+ Veuillez réessayer plus tard.
+
+
+----------fr--
diff --git a/docs/error/HTTP_UNAUTHORIZED.html.var b/docs/error/HTTP_UNAUTHORIZED.html.var
new file mode 100644
index 00000000000..4152b66146b
--- /dev/null
+++ b/docs/error/HTTP_UNAUTHORIZED.html.var
@@ -0,0 +1,84 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Der Server konnte nicht verifizieren, ob Sie authorisiert sind,
+ auf den URL "" zuzugreifen.
+ Entweder wurden falsche Referenzen (z.B. ein falsches Passwort)
+ angeben oder ihr Browser versteht nicht, wie die geforderten
+ Referenzen zu übermitteln sind.
+
+
+
+ Sofern Sie für den Zugriff berechtigt sind, überprüfen Sie bitte
+ die eingegebene User-ID und das Passwort und versuchen es erneut.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ This server could not verify that you are authorized to access
+ the URL "".
+ You either supplied the wrong credentials (e.g., bad password), or your
+ browser doesn't understand how to supply the credentials required.
+
+
+
+ In case you are allowed to request the document, please
+ check your user-id and password and try again.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ El servidor no puede certificar que usted este autorizado
+ para accesar el URL "".
+ Usted pudo suministrar información incorrecta accidentalmente
+ (ejem. una contraseña inválida) o, el buscador no sabe
+ como suministrar la información requerida.
+
+
+
+ En caso de que a usted le este permitido el uso del
+ documento requerido, le solicitamos de la manera mas atenta
+ que porfavor vuelva a intentar la operación suministrando
+ nuevamente su numero de identificación y su contraseña.
+
+ Muchas Gracias.
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Ce server n'a pas été en mesure de vérifier que
+ vous êtes autorisé à accéder à cette
+ URL "".
+
+ Vous avez ou bien fourni des coordonnées erronées
+ (p.ex. mot de passe inexact) ou bien votre navigateur ne parvient
+ pas à fournir les données exactes.
+
+
+
+ Si vous êtez autorisé à requérir le document,
+ veuillez vérifier votre nom d'utilisateur et votre mot de passe
+ et réessayer.
+
+
+----------fr--
diff --git a/docs/error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var b/docs/error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
new file mode 100644
index 00000000000..78c48bd2c42
--- /dev/null
+++ b/docs/error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
@@ -0,0 +1,45 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Das bei der Anfrage übermittelte Format (media type)
+ wird vom Server nicht unterstützt.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ The server does not support the media type transmitted in the request.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ Los datos de su solicitud no se encuentran en
+ un formato aceptado por este recurso.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+Le serveur ne supporte pas le type de média utilisé dans votre requête.
+
+
+----------fr--
diff --git a/docs/error/HTTP_VARIANT_ALSO_VARIES.html.var b/docs/error/HTTP_VARIANT_ALSO_VARIES.html.var
new file mode 100644
index 00000000000..b558284f477
--- /dev/null
+++ b/docs/error/HTTP_VARIANT_ALSO_VARIES.html.var
@@ -0,0 +1,51 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+
+
+
+ Ein Zugriff auf das angeforderte Objekt bzw. einer
+ Variante dieses Objektes ist nicht möglich, da es ebenfalls
+ ein variables Objekt darstellt.
+
+
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+
+
+
+ A variant for the requested entity
+ is itself a negotiable resource.
+ Access not possible.
+
+
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+
+
+
+ No es posible tener acceso debido a que
+ una variante de la solicitud es por si
+ misma un recurso negociable.
+
+
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+
+
+
+ Une variante pour l'entité requise
+ est elle-même une ressource négociable.
+ L'accès est impossible.
+
+
+----------fr--
diff --git a/docs/error/contact.html.var b/docs/error/contact.html.var
new file mode 100644
index 00000000000..f39136b6373
--- /dev/null
+++ b/docs/error/contact.html.var
@@ -0,0 +1,30 @@
+Content-language: de
+Content-type: text/html
+Body:----------de--
+ Sofern Sie dies für eine Fehlfunktion des Servers halten,
+ informieren Sie bitte den
+ ">Webmaster
+ hierüber.
+----------de--
+
+Content-language: en
+Content-type: text/html
+Body:----------en--
+ In case you think this is a server error, please contact
+ the ">Webmaster
+----------en--
+
+Content-language: es
+Content-type: text/html
+Body:----------es--
+Favor de contactar al
+">Webmaster
+en caso de que usted crea que existe un error en el servidor.
+----------es--
+
+Content-language: fr
+Content-type: text/html
+Body:----------fr--
+Si vous pensez qu'il s'agit d'une erreur du serveur, veuillez contacter
+le ">gestionnaire du site
+----------fr--
diff --git a/docs/error/include/bottom.html b/docs/error/include/bottom.html
new file mode 100644
index 00000000000..a3b23698d37
--- /dev/null
+++ b/docs/error/include/bottom.html
@@ -0,0 +1,12 @@
+
+
+
+
+ rightleft>
+
+
+
+
+Error
+
+
diff --git a/docs/error/include/spacer.html b/docs/error/include/spacer.html
new file mode 100644
index 00000000000..70c5b25f4a8
--- /dev/null
+++ b/docs/error/include/spacer.html
@@ -0,0 +1 @@
+
diff --git a/docs/icons/a.png b/docs/icons/a.png
new file mode 100644
index 00000000000..c1840256dcf
Binary files /dev/null and b/docs/icons/a.png differ
diff --git a/docs/icons/alert.black.png b/docs/icons/alert.black.png
new file mode 100644
index 00000000000..af6b1246ad7
Binary files /dev/null and b/docs/icons/alert.black.png differ
diff --git a/docs/icons/alert.red.png b/docs/icons/alert.red.png
new file mode 100644
index 00000000000..b9222fd5246
Binary files /dev/null and b/docs/icons/alert.red.png differ
diff --git a/docs/icons/apache_pb.png b/docs/icons/apache_pb.png
new file mode 100644
index 00000000000..eb99a8cd393
Binary files /dev/null and b/docs/icons/apache_pb.png differ
diff --git a/docs/icons/apache_pb2.png b/docs/icons/apache_pb2.png
new file mode 100644
index 00000000000..28baa70fb8c
Binary files /dev/null and b/docs/icons/apache_pb2.png differ
diff --git a/docs/icons/back.png b/docs/icons/back.png
new file mode 100644
index 00000000000..2d8d353bbc7
Binary files /dev/null and b/docs/icons/back.png differ
diff --git a/docs/icons/ball.gray.png b/docs/icons/ball.gray.png
new file mode 100644
index 00000000000..7b756f2d82d
Binary files /dev/null and b/docs/icons/ball.gray.png differ
diff --git a/docs/icons/ball.red.png b/docs/icons/ball.red.png
new file mode 100644
index 00000000000..05f3e50629c
Binary files /dev/null and b/docs/icons/ball.red.png differ
diff --git a/docs/icons/binary.png b/docs/icons/binary.png
new file mode 100644
index 00000000000..c5119d1e1ea
Binary files /dev/null and b/docs/icons/binary.png differ
diff --git a/docs/icons/binhex.png b/docs/icons/binhex.png
new file mode 100644
index 00000000000..eff532202d3
Binary files /dev/null and b/docs/icons/binhex.png differ
diff --git a/docs/icons/blank.png b/docs/icons/blank.png
new file mode 100644
index 00000000000..3802c03c9c8
Binary files /dev/null and b/docs/icons/blank.png differ
diff --git a/docs/icons/bomb.png b/docs/icons/bomb.png
new file mode 100644
index 00000000000..5261a0575e3
Binary files /dev/null and b/docs/icons/bomb.png differ
diff --git a/docs/icons/box1.png b/docs/icons/box1.png
new file mode 100644
index 00000000000..c55fccf8dc8
Binary files /dev/null and b/docs/icons/box1.png differ
diff --git a/docs/icons/box2.png b/docs/icons/box2.png
new file mode 100644
index 00000000000..26d14325d97
Binary files /dev/null and b/docs/icons/box2.png differ
diff --git a/docs/icons/broken.png b/docs/icons/broken.png
new file mode 100644
index 00000000000..e8fd150a339
Binary files /dev/null and b/docs/icons/broken.png differ
diff --git a/docs/icons/burst.png b/docs/icons/burst.png
new file mode 100644
index 00000000000..2329898f2a4
Binary files /dev/null and b/docs/icons/burst.png differ
diff --git a/docs/icons/c.png b/docs/icons/c.png
new file mode 100644
index 00000000000..41593b36b36
Binary files /dev/null and b/docs/icons/c.png differ
diff --git a/docs/icons/comp.blue.png b/docs/icons/comp.blue.png
new file mode 100644
index 00000000000..60ff156deb9
Binary files /dev/null and b/docs/icons/comp.blue.png differ
diff --git a/docs/icons/comp.gray.png b/docs/icons/comp.gray.png
new file mode 100644
index 00000000000..01538f8f316
Binary files /dev/null and b/docs/icons/comp.gray.png differ
diff --git a/docs/icons/compressed.png b/docs/icons/compressed.png
new file mode 100644
index 00000000000..de7276dbc08
Binary files /dev/null and b/docs/icons/compressed.png differ
diff --git a/docs/icons/continued.png b/docs/icons/continued.png
new file mode 100644
index 00000000000..8f656e27f24
Binary files /dev/null and b/docs/icons/continued.png differ
diff --git a/docs/icons/dir.png b/docs/icons/dir.png
new file mode 100644
index 00000000000..6b97905067e
Binary files /dev/null and b/docs/icons/dir.png differ
diff --git a/docs/icons/down.png b/docs/icons/down.png
new file mode 100644
index 00000000000..be3904b0451
Binary files /dev/null and b/docs/icons/down.png differ
diff --git a/docs/icons/dvi.png b/docs/icons/dvi.png
new file mode 100644
index 00000000000..19c417f227b
Binary files /dev/null and b/docs/icons/dvi.png differ
diff --git a/docs/icons/f.png b/docs/icons/f.png
new file mode 100644
index 00000000000..c946f5b3165
Binary files /dev/null and b/docs/icons/f.png differ
diff --git a/docs/icons/folder.open.png b/docs/icons/folder.open.png
new file mode 100644
index 00000000000..dd2d7e0cc2d
Binary files /dev/null and b/docs/icons/folder.open.png differ
diff --git a/docs/icons/folder.png b/docs/icons/folder.png
new file mode 100644
index 00000000000..6b97905067e
Binary files /dev/null and b/docs/icons/folder.png differ
diff --git a/docs/icons/folder.sec.png b/docs/icons/folder.sec.png
new file mode 100644
index 00000000000..833f59ac517
Binary files /dev/null and b/docs/icons/folder.sec.png differ
diff --git a/docs/icons/forward.png b/docs/icons/forward.png
new file mode 100644
index 00000000000..c5584a4c306
Binary files /dev/null and b/docs/icons/forward.png differ
diff --git a/docs/icons/generic.png b/docs/icons/generic.png
new file mode 100644
index 00000000000..0227cabb5ce
Binary files /dev/null and b/docs/icons/generic.png differ
diff --git a/docs/icons/generic.red.png b/docs/icons/generic.red.png
new file mode 100644
index 00000000000..be63249beb5
Binary files /dev/null and b/docs/icons/generic.red.png differ
diff --git a/docs/icons/generic.sec.png b/docs/icons/generic.sec.png
new file mode 100644
index 00000000000..0bd3d96bdcd
Binary files /dev/null and b/docs/icons/generic.sec.png differ
diff --git a/docs/icons/hand.right.png b/docs/icons/hand.right.png
new file mode 100644
index 00000000000..93035c658ab
Binary files /dev/null and b/docs/icons/hand.right.png differ
diff --git a/docs/icons/hand.up.png b/docs/icons/hand.up.png
new file mode 100644
index 00000000000..1405a6f1562
Binary files /dev/null and b/docs/icons/hand.up.png differ
diff --git a/docs/icons/icon.sheet.png b/docs/icons/icon.sheet.png
new file mode 100644
index 00000000000..b875cb6b1c1
Binary files /dev/null and b/docs/icons/icon.sheet.png differ
diff --git a/docs/icons/image1.png b/docs/icons/image1.png
new file mode 100644
index 00000000000..c1374fde333
Binary files /dev/null and b/docs/icons/image1.png differ
diff --git a/docs/icons/image2.png b/docs/icons/image2.png
new file mode 100644
index 00000000000..606d4fb87e5
Binary files /dev/null and b/docs/icons/image2.png differ
diff --git a/docs/icons/image3.png b/docs/icons/image3.png
new file mode 100644
index 00000000000..701fb1e1359
Binary files /dev/null and b/docs/icons/image3.png differ
diff --git a/docs/icons/index.png b/docs/icons/index.png
new file mode 100644
index 00000000000..9a0de350582
Binary files /dev/null and b/docs/icons/index.png differ
diff --git a/docs/icons/layout.png b/docs/icons/layout.png
new file mode 100644
index 00000000000..0a97c1c475f
Binary files /dev/null and b/docs/icons/layout.png differ
diff --git a/docs/icons/left.png b/docs/icons/left.png
new file mode 100644
index 00000000000..d6e2404a811
Binary files /dev/null and b/docs/icons/left.png differ
diff --git a/docs/icons/link.png b/docs/icons/link.png
new file mode 100644
index 00000000000..4714d0ef40a
Binary files /dev/null and b/docs/icons/link.png differ
diff --git a/docs/icons/movie.png b/docs/icons/movie.png
new file mode 100644
index 00000000000..5615180de88
Binary files /dev/null and b/docs/icons/movie.png differ
diff --git a/docs/icons/p.png b/docs/icons/p.png
new file mode 100644
index 00000000000..3fbe0e8801e
Binary files /dev/null and b/docs/icons/p.png differ
diff --git a/docs/icons/patch.png b/docs/icons/patch.png
new file mode 100644
index 00000000000..808ed7865fe
Binary files /dev/null and b/docs/icons/patch.png differ
diff --git a/docs/icons/pdf.png b/docs/icons/pdf.png
new file mode 100644
index 00000000000..516142bb47b
Binary files /dev/null and b/docs/icons/pdf.png differ
diff --git a/docs/icons/pie0.png b/docs/icons/pie0.png
new file mode 100644
index 00000000000..12e0200c97f
Binary files /dev/null and b/docs/icons/pie0.png differ
diff --git a/docs/icons/pie1.png b/docs/icons/pie1.png
new file mode 100644
index 00000000000..c44c793ed8b
Binary files /dev/null and b/docs/icons/pie1.png differ
diff --git a/docs/icons/pie2.png b/docs/icons/pie2.png
new file mode 100644
index 00000000000..e0b7167d913
Binary files /dev/null and b/docs/icons/pie2.png differ
diff --git a/docs/icons/pie3.png b/docs/icons/pie3.png
new file mode 100644
index 00000000000..820a3c35fa9
Binary files /dev/null and b/docs/icons/pie3.png differ
diff --git a/docs/icons/pie4.png b/docs/icons/pie4.png
new file mode 100644
index 00000000000..35490d857c7
Binary files /dev/null and b/docs/icons/pie4.png differ
diff --git a/docs/icons/pie5.png b/docs/icons/pie5.png
new file mode 100644
index 00000000000..359b7d377f4
Binary files /dev/null and b/docs/icons/pie5.png differ
diff --git a/docs/icons/pie6.png b/docs/icons/pie6.png
new file mode 100644
index 00000000000..4b293eae18c
Binary files /dev/null and b/docs/icons/pie6.png differ
diff --git a/docs/icons/pie7.png b/docs/icons/pie7.png
new file mode 100644
index 00000000000..6bfa2d06ae2
Binary files /dev/null and b/docs/icons/pie7.png differ
diff --git a/docs/icons/pie8.png b/docs/icons/pie8.png
new file mode 100644
index 00000000000..716cf2822bf
Binary files /dev/null and b/docs/icons/pie8.png differ
diff --git a/docs/icons/portal.png b/docs/icons/portal.png
new file mode 100644
index 00000000000..937c0f87cd6
Binary files /dev/null and b/docs/icons/portal.png differ
diff --git a/docs/icons/ps.png b/docs/icons/ps.png
new file mode 100644
index 00000000000..ccccf730b6c
Binary files /dev/null and b/docs/icons/ps.png differ
diff --git a/docs/icons/quill.png b/docs/icons/quill.png
new file mode 100644
index 00000000000..b697770a882
Binary files /dev/null and b/docs/icons/quill.png differ
diff --git a/docs/icons/right.png b/docs/icons/right.png
new file mode 100644
index 00000000000..41f8529a84e
Binary files /dev/null and b/docs/icons/right.png differ
diff --git a/docs/icons/screw1.png b/docs/icons/screw1.png
new file mode 100644
index 00000000000..11673ab97dc
Binary files /dev/null and b/docs/icons/screw1.png differ
diff --git a/docs/icons/screw2.png b/docs/icons/screw2.png
new file mode 100644
index 00000000000..5d7d2cf65e9
Binary files /dev/null and b/docs/icons/screw2.png differ
diff --git a/docs/icons/script.png b/docs/icons/script.png
new file mode 100644
index 00000000000..2520570a775
Binary files /dev/null and b/docs/icons/script.png differ
diff --git a/docs/icons/small/back.png b/docs/icons/small/back.png
new file mode 100644
index 00000000000..2257df2140d
Binary files /dev/null and b/docs/icons/small/back.png differ
diff --git a/docs/icons/small/binary.png b/docs/icons/small/binary.png
new file mode 100644
index 00000000000..2e2e1b073d6
Binary files /dev/null and b/docs/icons/small/binary.png differ
diff --git a/docs/icons/small/binhex.png b/docs/icons/small/binhex.png
new file mode 100644
index 00000000000..9deab419b61
Binary files /dev/null and b/docs/icons/small/binhex.png differ
diff --git a/docs/icons/small/blank.png b/docs/icons/small/blank.png
new file mode 100644
index 00000000000..86f57a504f7
Binary files /dev/null and b/docs/icons/small/blank.png differ
diff --git a/docs/icons/small/broken.png b/docs/icons/small/broken.png
new file mode 100644
index 00000000000..79c998c8c31
Binary files /dev/null and b/docs/icons/small/broken.png differ
diff --git a/docs/icons/small/burst.png b/docs/icons/small/burst.png
new file mode 100644
index 00000000000..2b21436c78e
Binary files /dev/null and b/docs/icons/small/burst.png differ
diff --git a/docs/icons/small/comp1.png b/docs/icons/small/comp1.png
new file mode 100644
index 00000000000..6d8c3459ed0
Binary files /dev/null and b/docs/icons/small/comp1.png differ
diff --git a/docs/icons/small/comp2.png b/docs/icons/small/comp2.png
new file mode 100644
index 00000000000..57f7ad197b8
Binary files /dev/null and b/docs/icons/small/comp2.png differ
diff --git a/docs/icons/small/compressed.png b/docs/icons/small/compressed.png
new file mode 100644
index 00000000000..43acd8b943d
Binary files /dev/null and b/docs/icons/small/compressed.png differ
diff --git a/docs/icons/small/continued.png b/docs/icons/small/continued.png
new file mode 100644
index 00000000000..db17c424650
Binary files /dev/null and b/docs/icons/small/continued.png differ
diff --git a/docs/icons/small/dir.png b/docs/icons/small/dir.png
new file mode 100644
index 00000000000..9bd6256bdbb
Binary files /dev/null and b/docs/icons/small/dir.png differ
diff --git a/docs/icons/small/dir2.png b/docs/icons/small/dir2.png
new file mode 100644
index 00000000000..836daf49ef2
Binary files /dev/null and b/docs/icons/small/dir2.png differ
diff --git a/docs/icons/small/doc.png b/docs/icons/small/doc.png
new file mode 100644
index 00000000000..c560df21d3c
Binary files /dev/null and b/docs/icons/small/doc.png differ
diff --git a/docs/icons/small/forward.png b/docs/icons/small/forward.png
new file mode 100644
index 00000000000..4ddbc61e142
Binary files /dev/null and b/docs/icons/small/forward.png differ
diff --git a/docs/icons/small/generic.png b/docs/icons/small/generic.png
new file mode 100644
index 00000000000..16374a12bbb
Binary files /dev/null and b/docs/icons/small/generic.png differ
diff --git a/docs/icons/small/generic2.png b/docs/icons/small/generic2.png
new file mode 100644
index 00000000000..40d60c1df23
Binary files /dev/null and b/docs/icons/small/generic2.png differ
diff --git a/docs/icons/small/generic3.png b/docs/icons/small/generic3.png
new file mode 100644
index 00000000000..aa38963afa2
Binary files /dev/null and b/docs/icons/small/generic3.png differ
diff --git a/docs/icons/small/image.png b/docs/icons/small/image.png
new file mode 100644
index 00000000000..d92f0a5fcc4
Binary files /dev/null and b/docs/icons/small/image.png differ
diff --git a/docs/icons/small/image2.png b/docs/icons/small/image2.png
new file mode 100644
index 00000000000..4049bda5619
Binary files /dev/null and b/docs/icons/small/image2.png differ
diff --git a/docs/icons/small/index.png b/docs/icons/small/index.png
new file mode 100644
index 00000000000..080453e2151
Binary files /dev/null and b/docs/icons/small/index.png differ
diff --git a/docs/icons/small/key.png b/docs/icons/small/key.png
new file mode 100644
index 00000000000..1a45f67df31
Binary files /dev/null and b/docs/icons/small/key.png differ
diff --git a/docs/icons/small/movie.png b/docs/icons/small/movie.png
new file mode 100644
index 00000000000..7c126042c9a
Binary files /dev/null and b/docs/icons/small/movie.png differ
diff --git a/docs/icons/small/patch.png b/docs/icons/small/patch.png
new file mode 100644
index 00000000000..c39f14435a0
Binary files /dev/null and b/docs/icons/small/patch.png differ
diff --git a/docs/icons/small/ps.png b/docs/icons/small/ps.png
new file mode 100644
index 00000000000..5c604230d07
Binary files /dev/null and b/docs/icons/small/ps.png differ
diff --git a/docs/icons/small/rainbow.png b/docs/icons/small/rainbow.png
new file mode 100644
index 00000000000..175053cb433
Binary files /dev/null and b/docs/icons/small/rainbow.png differ
diff --git a/docs/icons/small/sound.png b/docs/icons/small/sound.png
new file mode 100644
index 00000000000..6e3e95d3d01
Binary files /dev/null and b/docs/icons/small/sound.png differ
diff --git a/docs/icons/small/sound2.png b/docs/icons/small/sound2.png
new file mode 100644
index 00000000000..bc46eb48fe5
Binary files /dev/null and b/docs/icons/small/sound2.png differ
diff --git a/docs/icons/small/tar.png b/docs/icons/small/tar.png
new file mode 100644
index 00000000000..12f0347bf9c
Binary files /dev/null and b/docs/icons/small/tar.png differ
diff --git a/docs/icons/small/text.png b/docs/icons/small/text.png
new file mode 100644
index 00000000000..b4e30f466d3
Binary files /dev/null and b/docs/icons/small/text.png differ
diff --git a/docs/icons/small/transfer.png b/docs/icons/small/transfer.png
new file mode 100644
index 00000000000..324048170a8
Binary files /dev/null and b/docs/icons/small/transfer.png differ
diff --git a/docs/icons/small/unknown.png b/docs/icons/small/unknown.png
new file mode 100644
index 00000000000..cad7e7a7aa0
Binary files /dev/null and b/docs/icons/small/unknown.png differ
diff --git a/docs/icons/small/uu.png b/docs/icons/small/uu.png
new file mode 100644
index 00000000000..ef87c82ee6c
Binary files /dev/null and b/docs/icons/small/uu.png differ
diff --git a/docs/icons/sound1.png b/docs/icons/sound1.png
new file mode 100644
index 00000000000..7a766be6cc8
Binary files /dev/null and b/docs/icons/sound1.png differ
diff --git a/docs/icons/sound2.png b/docs/icons/sound2.png
new file mode 100644
index 00000000000..45112909398
Binary files /dev/null and b/docs/icons/sound2.png differ
diff --git a/docs/icons/sphere1.png b/docs/icons/sphere1.png
new file mode 100644
index 00000000000..2198ae89ec4
Binary files /dev/null and b/docs/icons/sphere1.png differ
diff --git a/docs/icons/sphere2.png b/docs/icons/sphere2.png
new file mode 100644
index 00000000000..257632ba46d
Binary files /dev/null and b/docs/icons/sphere2.png differ
diff --git a/docs/icons/tar.png b/docs/icons/tar.png
new file mode 100644
index 00000000000..6c40521ff80
Binary files /dev/null and b/docs/icons/tar.png differ
diff --git a/docs/icons/tex.png b/docs/icons/tex.png
new file mode 100644
index 00000000000..906622d3844
Binary files /dev/null and b/docs/icons/tex.png differ
diff --git a/docs/icons/text.png b/docs/icons/text.png
new file mode 100644
index 00000000000..34d0edf86e4
Binary files /dev/null and b/docs/icons/text.png differ
diff --git a/docs/icons/transfer.png b/docs/icons/transfer.png
new file mode 100644
index 00000000000..efaf17b682f
Binary files /dev/null and b/docs/icons/transfer.png differ
diff --git a/docs/icons/unknown.png b/docs/icons/unknown.png
new file mode 100644
index 00000000000..7c241c383c0
Binary files /dev/null and b/docs/icons/unknown.png differ
diff --git a/docs/icons/up.png b/docs/icons/up.png
new file mode 100644
index 00000000000..a69ea00c5b7
Binary files /dev/null and b/docs/icons/up.png differ
diff --git a/docs/icons/uu.png b/docs/icons/uu.png
new file mode 100644
index 00000000000..b1d1a8579d5
Binary files /dev/null and b/docs/icons/uu.png differ
diff --git a/docs/icons/uuencoded.png b/docs/icons/uuencoded.png
new file mode 100644
index 00000000000..b1d1a8579d5
Binary files /dev/null and b/docs/icons/uuencoded.png differ
diff --git a/docs/icons/world1.png b/docs/icons/world1.png
new file mode 100644
index 00000000000..3a65c00d846
Binary files /dev/null and b/docs/icons/world1.png differ
diff --git a/docs/icons/world2.png b/docs/icons/world2.png
new file mode 100644
index 00000000000..9f8a3ea4b35
Binary files /dev/null and b/docs/icons/world2.png differ
diff --git a/docs/manual/developer/documenting.html b/docs/manual/developer/documenting.html
new file mode 100644
index 00000000000..8f8163f426e
--- /dev/null
+++ b/docs/manual/developer/documenting.html
@@ -0,0 +1,64 @@
+
+
+
+Documenting Apache 2.0
+
+
+
+
+
+
+
Documentating Apache 2.0
+
+
Apache 2.0 uses DoxyGen to document the API's and global variables in the
+ the code. This will explain the basics of how to document using DoxyGen.
+
+
To start a documentation block, use /**
+ To end a documentation block, use */
+
+
In the middle of the block, there are multiple tags we can use:
+
+ Description of this functions purpose
+ @param parameter_name description
+
+
+
The deffunc is not always necessary. DoxyGen does not have a full parser
+ in it, so any prototype that use a macro in the return type declaration
+ is too complex for scandoc. Those functions require a deffunc.
+
+
An example (using &> rather than >):
+
+/**
+ * return the final element of the pathname
+ * @param pathname The path to get the final element of
+ * @return the final element of the path
+ * @tip Examples:
+ * <pre>
+ * "/foo/bar/gum" -&> "gum"
+ * "/foo/bar/gum/" -&> ""
+ * "gum" -&> "gum"
+ * "wi\\n32\\stuff" -&> "stuff"
+ * </pre>
+ * @deffunc const char * ap_filename_of_pathname(const char *pathname)
+ */
+
+
+
At the top of the header file, always include:
+
+/**
+ * @package Name of library header
+ */
+
+
+
ScanDoc uses a new html file for each package. The html files are named
+ {Name_of_library_header}.html, so try to be concise with your names.
Warning - this is a first (fast) draft that needs further revision!
+
+
Several changes in Apache 2.0 affect the internal request processing
+ mechanics. Module authors need to be aware of these changes so they
+ may take advantage of the optimizations and security enhancements.
+
+
The first major change is to the subrequest and redirect mechanisms.
+ There were a number of different code paths in Apache 1.3 to attempt
+ to optimize subrequest or redirect behavior. As patches were introduced
+ to 2.0, these optimizations (and the server behavior) were quickly broken
+ due to this duplication of code. All duplicate code has been folded
+ back into ap_process_internal_request() to prevent the
+ code from falling out of sync again.
+
+
This means that much of the existing code was 'unoptimized'. It is
+ the Apache HTTP Project's first goal to create a robust and correct
+ implementation of the HTTP server RFC. Additional goals include
+ security, scalability and optimization. New methods were sought to
+ optimize the server (beyond the performance of Apache 1.3) without
+ introducing fragile or insecure code.
+
+
The Request Processing Cycle
+
+
All requests pass through ap_process_request_internal()
+ in request.c, including subrequests and redirects. If a module doesn't
+ pass generated requests through this code, the author is cautioned that
+ the module may be broken by future changes to request processing.
+
+
To streamline requests, the module author can take advantage of the
+ hooks offered to drop out of the request cycle early, or to bypass
+ core Apache hooks which are irrelevant (and costly in terms of CPU.)
+
+
The Request Parsing Phase
+
+
Unescapes the URL
+
+
The request's parsed_uri path is unescaped, once and only once, at the
+ beginning of internal request processing.
+
+
This step is bypassed if the proxyreq flag is set, or the parsed_uri.path
+ element is unset. The module has no further control of this one-time
+ unescape operation, either failing to unescape or multiply unescaping
+ the URL leads to security reprecussions.
+
+
Strips Parent and This Elements from the URI
+
+
All /../ and /./ elements are removed by
+ ap_getparents(). This helps to ensure the path is (nearly)
+ absolute before the request processing continues.
+
+
This step cannot be bypassed.
+
+
Initial URI Location Walk
+
+
Every request is subject to an ap_location_walk() call.
+ This ensures that <Location > sections are consistently enforced for
+ all requests. If the request is an internal redirect or a sub-request,
+ it may borrow some or all of the processing from the previous or parent
+ request's ap_location_walk, so this step is generally very efficient
+ after processing the main request.
+
+
Hook: translate_name
+
+
Modules can determine the file name, or alter the given URI in this step.
+ For example, mod_vhost_alias will translate the URI's path into the
+ configured virtual host, mod_alias will translate the path to an alias
+ path, and if the request falls back on the core, the DocumentRoot is
+ prepended to the request resource.
+
+
If all modules DECLINE this phase, an error 500 is returned to the browser,
+ and a "couldn't translate name" error is logged automatically.
+
+
Hook: map_to_storage
+
+
After the file or correct URI was determined, the appropriate per-dir
+ configurations are merged together. For example, mod_proxy compares
+ and merges the appropriate <Proxy > sections. If the URI is nothing
+ more than a local (non-proxy) TRACE request, the core handles the
+ request and returns DONE. If no module answers this hook with OK or
+ DONE, the core will run the request filename against the <Directory >
+ and <Files > sections. If the request 'filename' isn't an absolute,
+ legal filename, a note is set for later termination.
+
+
Initial URI Location Walk
+
+
Every request is hardened by a second ap_location_walk()
+ call. This reassures that a translated request is still subjected to
+ the configured <Location > sections. The request again borrows
+ some or all of the processing from it's previous location_walk above,
+ so this step is almost always very efficient unless the translated URI
+ mapped to a substantially different path or Virtual Host.
+
+
Hook: header_parser
+
+
The main request then parses the client's headers. This prepares
+the remaining request processing steps to better serve the client's
+request.
+
+
The Security Phase
+
+
Needs Documentation. Code is;
+
+ switch (ap_satisfies(r)) {
+ case SATISFY_ALL:
+ case SATISFY_NOSPEC:
+ if ((access_status = ap_run_access_checker(r)) != 0) {
+ return decl_die(access_status, "check access", r);
+ }
+ if (ap_some_auth_required(r)) {
+ if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
+ return decl_die(access_status, ap_auth_type(r)
+ ? "check user. No user file?"
+ : "perform authentication. AuthType not set!", r);
+ }
+ if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
+ return decl_die(access_status, ap_auth_type(r)
+ ? "check access. No groups file?"
+ : "perform authentication. AuthType not set!", r);
+ }
+ }
+ break;
+ case SATISFY_ANY:
+ if (((access_status = ap_run_access_checker(r)) != 0) || !ap_auth_type(r)) {
+ if (!ap_some_auth_required(r)) {
+ return decl_die(access_status, ap_auth_type(r)
+ ? "check access"
+ : "perform authentication. AuthType not set!", r);
+ }
+ if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
+ return decl_die(access_status, ap_auth_type(r)
+ ? "check user. No user file?"
+ : "perform authentication. AuthType not set!", r);
+ }
+ if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
+ return decl_die(access_status, ap_auth_type(r)
+ ? "check access. No groups file?"
+ : "perform authentication. AuthType not set!", r);
+ }
+ }
+ break;
+ }
+
+
The Preparation Phase
+
+
Hook: type_checker
+
+
The modules have an opportunity to test the URI or filename against
+ the target resource, and set mime information for the request. Both
+ mod_mime and mod_mime_magic use this phase to compare the file name
+ or contents against the administrator's configuration and set the
+ content type, language, character set and request handler. Some
+ modules may set up their filters or other request handling parameters
+ at this time.
+
+
If all modules DECLINE this phase, an error 500 is returned to the browser,
+ and a "couldn't find types" error is logged automatically.
+
+
Hook: fixups
+
+
Many modules are 'trounced' by some phase above. The fixups phase is
+ used by modules to 'reassert' their ownership or force the request's
+ fields to their appropriate values. It isn't always the cleanest
+ mechanism, but occasionally it's the only option.
+
+
Hook: insert_filter
+
+
Modules that transform the content in some way can insert their values
+ and override existing filters, such that if the user configured a more
+ advanced filter out-of-order, then the module can move it's order as
+ need be.
+
+
The Handler Phase
+
+
This phase is not part of the processing in
+ ap_process_request_internal(). Many modules prepare one
+ or more subrequests prior to creating any content at all. After the
+ core, or a module calls ap_process_request_internal() it
+ then calls ap_invoke_handler() to generate the request.
+
+
Hook: handler
+
+
The module finally has a chance to serve the request in it's handler
+ hook. Note that not every prepared request is sent to the handler
+ hook. Many modules, such as mod_autoindex, will create subrequests
+ for a given URI, and then never serve the subrequest, but simply
+ lists it for the user. Remember not to put required teardown from
+ the hooks above into this module, but register pool cleanups against
+ the request pool to free resources as required.
+ The latest version of this FAQ is always available from the main
+ Apache web site, at <http://httpd.apache.org/docs-2.0/faq/>.
+ In addition, you can view this FAQ all in one page for easy searching and
+ printing.
+
+
+
Since Apache 2.0 is very new, we don't yet know what the
+ Frequently Asked Questions will be. While this section
+ fills up, you should also consult the Apache 1.3 FAQ
+ to see if your question is answered there.
+ If you are having trouble with your Apache server software, you should
+ take the following steps:
+
+
+
Check the errorlog!
+
+ Apache tries to be helpful when it encounters a problem. In many
+ cases, it will provide some details by writing one or messages to
+ the server error log. Sometimes this is enough for you to diagnose
+ & fix the problem yourself (such as file permissions or the like).
+ The default location of the error log is
+ /usr/local/apache/logs/error_log, but see the
+ ErrorLog
+ directive in your config files for the location on your server.
+
+ The latest version of the Apache Frequently-Asked Questions list can
+ always be found at the main Apache web site.
+
+
+
Check the Apache bug database
+
+ Most problems that get reported to The Apache Group are recorded in
+ the
+ bug database.
+ Please check the existing reports, open
+ and closed, before adding one. If you find
+ that your issue has already been reported, please don't add
+ a "me, too" report. If the original report isn't closed
+ yet, we suggest that you check it periodically. You might also
+ consider contacting the original submitter, because there may be an
+ email exchange going on about the issue that isn't getting recorded
+ in the database.
+
+
+
Ask in the comp.infosystems.www.servers.unix
+ or comp.infosystems.www.servers.ms-windows USENET
+ newsgroup (as appropriate for the platform you use).
+
+ A lot of common problems never make it to the bug database because
+ there's already high Q&A traffic about them in the
+ comp.infosystems.www.servers.unix
+ newsgroup. Many Apache users, and some of the developers, can be
+ found roaming its virtual halls, so it is suggested that you seek
+ wisdom there. The chances are good that you'll get a faster answer
+ there than from the bug database, even if you don't see
+ your question already posted.
+
+
+
If all else fails, report the problem in the bug
+ database
+
+ If you've gone through those steps above that are appropriate and
+ have obtained no relief, then please do let The Apache
+ Group know about the problem by
+ logging a bug report.
+
+
+ If your problem involves the server crashing and generating a core
+ dump, please include a backtrace (if possible). As an example,
+
+
+
+
# cd ServerRoot
+ # dbx httpd core
+ (dbx) where
+
+
+
+
+ (Substitute the appropriate locations for your
+ ServerRoot and your httpd and
+ core files. You may have to use gdb
+ instead of dbx.)
+
+ There is no official support for Apache. None of the developers want to
+ be swamped by a flood of trivial questions that can be resolved elsewhere.
+ Bug reports and suggestions should be sent via
+ the bug report page.
+ Other questions should be directed to the
+ comp.infosystems.www.servers.unix or comp.infosystems.www.servers.ms-windows
+ newsgroup (as appropriate for the platform you use), where some of the
+ Apache team lurk, in the company of many other httpd gurus who
+ should be able to help.
+
+
+ Commercial support for Apache is, however, available from a number
+ of third parties.
+
Authentication is any process by which you verify that
+ someone is who they claim they are. Authorization is any
+ process by which someone is allowed to be where they want to
+ go, or to have information that they want to have.
If you have information on your web site that is sensitive
+ or intended for only a small group of people, the techniques in
+ this article will help you make sure that the people that see
+ those pages are the people that you wanted to see them.
+
+
This article covers the "standard" way of protecting parts of your
+ web site that most of you are going to use.
The directives discussed in this article will need to go either
+ in your main server configuration file, or in per-directory
+ configuration files (.htaccess files).
+
+
If you plan to use .htaccess files, you will need to
+ have a server configuration that permits putting authentication
+ directives in these files. This is done with the
+ AllowOverride
+ directive, which specifies which directives, if any, may be put in
+ per-directory configuration files.
+
+
Since we're talking here about authentication, you will need an
+ AllowOverride directive like the following:
+
+
+ AllowOverride AuthConfig
+
+
+
Or, if you are just going to put the directives directly in your
+ main server configuration file, you will of course need to have
+ write permission to that file.
+
+
And you'll need to know a little bit about the directory
+ structure of your server, in order to know where some files are
+ kept. This should not be terribly difficult, and I'll try to
+ make this clear when we come to that point.
Here's the basics of password protecting a directory on your
+ server.
+
+
You'll need to create a password file. This file should be
+ placed somewhere outside of your document directory. This is so
+ that folks cannot download the password file. For example, if
+ your documents are served out of
+ /usr/local/apache/htdocs you might want to put the
+ password file(s) in /usr/local/apache/passwd.
+
+
To create the file, use the htpasswd utility
+ that came with Apache. This be located in the bin
+ directory of wherever you installed Apache. To create the file,
+ type:
htpasswd will ask you for the password, and
+ then ask you to type it again to confirm it:
+
+ # htpasswd -c /usr/local/apache/passwd/passwords rbowen
+ New password: mypassword
+ Re-type new password: mypassword
+ Adding password for user rbowen
+
+
+
If htpasswd is not in your path, of course
+ you'll have to type the full path to the file to get it to run.
+ On my server, it's located at
+ /usr/local/apache/bin/htpasswd
+
+
Next, you'll need to create a file in the directory you want
+ to protect. This file is usually called .htaccess,
+ although on Windows it's called htaccess (without
+ the leading period.) .htaccess needs to contain
+ the following lines:
The next time that you load a file from that directory, you
+ should see the familiar username/password dialog box pop up. If
+ you don't chances are pretty good that you are not permitted to
+ use .htaccess files in the directory in
+ question.
The directives above only let one person (specifically
+ someone with a username of rbowen) into the
+ directory. In most cases, you'll want to let more than one
+ person in. This is where the AuthGroupFile comes
+ in. In the example above, we've pointed
+ AuthGroupFile to /dev/null, which is
+ Unix-speak for "nowhere", or "off into space." (The Windows
+ NT equivalent of this is nul.)
+
+
If you want to let more than one person in, you'll need to
+ create a group file that associates group names with a list of
+ users in that group. The format of this file is pretty simple,
+ and you can create it with your favorite editor. The contents
+ of the file will look like this:
+
+ GroupName: rbowen dpitts sungo rshersey
+
+
+
That's just a list of the members of the group in a long
+ line separated by spaces.
+
+
To add a user to your already existing password file,
+ type:
You'll get the same response as before, but it will be
+ appended to the existing file, rather than creating a new file.
+ (It's the -c that makes it create a new password
+ file.
+
+
Now, you need to modify your .htaccess file to
+ look like the following:
Now, anyone that is listed in the group
+ GroupName, and has an entry in the
+ password file, will be let in, if they type the
+ correct password.
+
+
There's another way to let multiple users in that is less
+ specific. Rather than creating a group file, you can just use
+ the following directive:
+
+ require valid-user
+
+
+
Using that rather than the require user rbowen
+ line will allow anyone in that is listed in the password file,
+ and who correctly enters their password. You can even emulate
+ the group behavior here, by just keeping a separate password
+ file for each group. The advantage of this approach is that
+ Apache only has to check one file, rather than two. The
+ disadvantage is that you have to maintain a bunch of password
+ files, and remember to reference th right one in the
+ AuthUserFile directive.
Because of the way that Basic authentication is specified,
+ your username and password must be verified every time you
+ request a document from the server. This is even if you're
+ reloading the same page, and for every image on the page (if
+ they come from a protected directory). As you can imagine, this
+ slows things down a little. The amount that it slows things
+ down is proportional to the size of the password file, because
+ it has to open up that file, and go down the list of users
+ until it gets to your name. And it has to do this every time a
+ page is loaded.
+
+
A consequence of this is that there's a practical limit to how many
+ users you can put in one password file. This limit will vary
+ depending on the performance of your particular server machine, but
+ you can expect to see slowdowns once you get above a few hundred
+ entries, and may wish to consider a different authentication method
+ at that time.
Authentication by username and password is only part of the
+ story. Frequently you want to let people in based on something
+ other than who they are. Something such as where they are
+ coming from.
+
+
The allow and deny directives let
+ you allow and deny access based on the host name, or host
+ address, of the machine requesting a document. The directive
+ goes hand-in-hand with these is the order
+ directive, which tells Apache in which order to apply the
+ filters.
+
+
The usage of these directives is:
+
+ allow from address
+
+
+
where address is an IP address (or a partial IP
+ address) or a fully qualified domain name (or a partial domain
+ name).
+
+
For example, if you have someone spamming your message
+ board, and you want to keep them out, you could do the
+ following:
+
+ deny from 205.252.46.165
+
+
+
Visitors coming from that address will not be able to see
+ the content behind this directive. If, instead, you have a
+ machine name, rather than an IP address, you can use that.
+
+ deny from host.example.com
+
+
+
And, if you'd like to block access from an entire domain,
+ you can specify just part of an address or domain name:
+
+ deny from 192.101.205
+ deny from cyberthugs.com
+ deny from ke
+
+
+
Using order will let you be sure that you are
+ actually restricting things to the group that you want to let
+ in, by combining a deny and an allow
+ directive:
+
+ order deny,allow
+ deny from all
+ allow from dev.example.com
+
+
+
Listing just the allow directive would not do
+ what you want, because it will let folks from that host in, in
+ addition to letting everyone in. What you want is to let
+ only those folks in.
Authentication is any process by which you verify that
+ someone is who they claim they are. Authorization is any
+ process by which someone is allowed to be where they want to
+ go, or to have information that they want to have.
If you have information on your web site that is sensitive
+ or intended for only a small group of people, the techniques in
+ this article will help you make sure that the people that see
+ those pages are the people that you wanted to see them.
+
+
This article covers the "standard" way of protecting parts of your
+ web site that most of you are going to use.
The directives discussed in this article will need to go either
+ in your main server configuration file, or in per-directory
+ configuration files (.htaccess files).
+
+
If you plan to use .htaccess files, you will need to
+ have a server configuration that permits putting authentication
+ directives in these files. This is done with the
+ AllowOverride
+ directive, which specifies which directives, if any, may be put in
+ per-directory configuration files.
+
+
Since we're talking here about authentication, you will need an
+ AllowOverride directive like the following:
+
+
+ AllowOverride AuthConfig
+
+
+
Or, if you are just going to put the directives directly in your
+ main server configuration file, you will of course need to have
+ write permission to that file.
+
+
And you'll need to know a little bit about the directory
+ structure of your server, in order to know where some files are
+ kept. This should not be terribly difficult, and I'll try to
+ make this clear when we come to that point.
Here's the basics of password protecting a directory on your
+ server.
+
+
You'll need to create a password file. This file should be
+ placed somewhere outside of your document directory. This is so
+ that folks cannot download the password file. For example, if
+ your documents are served out of
+ /usr/local/apache/htdocs you might want to put the
+ password file(s) in /usr/local/apache/passwd.
+
+
To create the file, use the htpasswd utility
+ that came with Apache. This be located in the bin
+ directory of wherever you installed Apache. To create the file,
+ type:
htpasswd will ask you for the password, and
+ then ask you to type it again to confirm it:
+
+ # htpasswd -c /usr/local/apache/passwd/passwords rbowen
+ New password: mypassword
+ Re-type new password: mypassword
+ Adding password for user rbowen
+
+
+
If htpasswd is not in your path, of course
+ you'll have to type the full path to the file to get it to run.
+ On my server, it's located at
+ /usr/local/apache/bin/htpasswd
+
+
Next, you'll need to create a file in the directory you want
+ to protect. This file is usually called .htaccess,
+ although on Windows it's called htaccess (without
+ the leading period.) .htaccess needs to contain
+ the following lines:
The next time that you load a file from that directory, you
+ should see the familiar username/password dialog box pop up. If
+ you don't chances are pretty good that you are not permitted to
+ use .htaccess files in the directory in
+ question.
The directives above only let one person (specifically
+ someone with a username of rbowen) into the
+ directory. In most cases, you'll want to let more than one
+ person in. This is where the AuthGroupFile comes
+ in. In the example above, we've pointed
+ AuthGroupFile to /dev/null, which is
+ Unix-speak for "nowhere", or "off into space." (The Windows
+ NT equivalent of this is nul.)
+
+
If you want to let more than one person in, you'll need to
+ create a group file that associates group names with a list of
+ users in that group. The format of this file is pretty simple,
+ and you can create it with your favorite editor. The contents
+ of the file will look like this:
+
+ GroupName: rbowen dpitts sungo rshersey
+
+
+
That's just a list of the members of the group in a long
+ line separated by spaces.
+
+
To add a user to your already existing password file,
+ type:
You'll get the same response as before, but it will be
+ appended to the existing file, rather than creating a new file.
+ (It's the -c that makes it create a new password
+ file.
+
+
Now, you need to modify your .htaccess file to
+ look like the following:
Now, anyone that is listed in the group
+ GroupName, and has an entry in the
+ password file, will be let in, if they type the
+ correct password.
+
+
There's another way to let multiple users in that is less
+ specific. Rather than creating a group file, you can just use
+ the following directive:
+
+ require valid-user
+
+
+
Using that rather than the require user rbowen
+ line will allow anyone in that is listed in the password file,
+ and who correctly enters their password. You can even emulate
+ the group behavior here, by just keeping a separate password
+ file for each group. The advantage of this approach is that
+ Apache only has to check one file, rather than two. The
+ disadvantage is that you have to maintain a bunch of password
+ files, and remember to reference th right one in the
+ AuthUserFile directive.
Because of the way that Basic authentication is specified,
+ your username and password must be verified every time you
+ request a document from the server. This is even if you're
+ reloading the same page, and for every image on the page (if
+ they come from a protected directory). As you can imagine, this
+ slows things down a little. The amount that it slows things
+ down is proportional to the size of the password file, because
+ it has to open up that file, and go down the list of users
+ until it gets to your name. And it has to do this every time a
+ page is loaded.
+
+
A consequence of this is that there's a practical limit to how many
+ users you can put in one password file. This limit will vary
+ depending on the performance of your particular server machine, but
+ you can expect to see slowdowns once you get above a few hundred
+ entries, and may wish to consider a different authentication method
+ at that time.
Authentication by username and password is only part of the
+ story. Frequently you want to let people in based on something
+ other than who they are. Something such as where they are
+ coming from.
+
+
The allow and deny directives let
+ you allow and deny access based on the host name, or host
+ address, of the machine requesting a document. The directive
+ goes hand-in-hand with these is the order
+ directive, which tells Apache in which order to apply the
+ filters.
+
+
The usage of these directives is:
+
+ allow from address
+
+
+
where address is an IP address (or a partial IP
+ address) or a fully qualified domain name (or a partial domain
+ name).
+
+
For example, if you have someone spamming your message
+ board, and you want to keep them out, you could do the
+ following:
+
+ deny from 205.252.46.165
+
+
+
Visitors coming from that address will not be able to see
+ the content behind this directive. If, instead, you have a
+ machine name, rather than an IP address, you can use that.
+
+ deny from host.example.com
+
+
+
And, if you'd like to block access from an entire domain,
+ you can specify just part of an address or domain name:
+
+ deny from 192.101.205
+ deny from cyberthugs.com
+ deny from ke
+
+
+
Using order will let you be sure that you are
+ actually restricting things to the group that you want to let
+ in, by combining a deny and an allow
+ directive:
+
+ order deny,allow
+ deny from all
+ allow from dev.example.com
+
+
+
Listing just the allow directive would not do
+ what you want, because it will let folks from that host in, in
+ addition to letting everyone in. What you want is to let
+ only those folks in.
You should also read the documentation for
+ mod_auth
+ which contains
+ some more information about how this all works.
+
+
+
diff --git a/docs/manual/images/custom_errordocs.png b/docs/manual/images/custom_errordocs.png
new file mode 100644
index 00000000000..11553cbdeec
Binary files /dev/null and b/docs/manual/images/custom_errordocs.png differ
diff --git a/docs/manual/images/mod_rewrite_fig1.png b/docs/manual/images/mod_rewrite_fig1.png
new file mode 100644
index 00000000000..f3a68d9e4c5
Binary files /dev/null and b/docs/manual/images/mod_rewrite_fig1.png differ
diff --git a/docs/manual/images/mod_rewrite_fig2.png b/docs/manual/images/mod_rewrite_fig2.png
new file mode 100644
index 00000000000..bc141be7694
Binary files /dev/null and b/docs/manual/images/mod_rewrite_fig2.png differ
diff --git a/docs/manual/logs.html b/docs/manual/logs.html
new file mode 100644
index 00000000000..d3ebf480c58
--- /dev/null
+++ b/docs/manual/logs.html
@@ -0,0 +1,580 @@
+
+
+
+Log Files - Apache HTTP Server
+
+
+
+
+
+
Log Files
+
+
In order to effectively manage a web server, it is necessary to get
+feedback about the activity and performance of the server as well as
+any problems that may be occuring. The Apache HTTP Server provides
+very comprehensive and flexible logging capabilities. This document
+describes how to configure the various log files, and how to
+understand what the logs contain.
Anyone who can write to the directory where Apache is writing a
+log file can almost certainly gain access to the uid that the server is
+started as, which is normally root. Do NOT give people write
+access to the directory the logs are stored in without being aware of
+the consequences; see the security tips
+document for details.
+
+
In addition, log files may contain information supplied directly
+by the client, without escaping. Therefore, it is possible for
+malicious clients to insert control-characters in the log files, so
+care must be taken in dealing with raw logs.
The server error log, whose name and location is set by the ErrorLog directive, is the most
+important log file. This is the place where Apache HTTPD will send
+diagnostic information and record any errors that it encounters in
+processing requests. It is the first place to look when a problem
+occurs with starting the server or with the operation of the server,
+since it will often contain details of what went wrong and how to fix
+it.
+
+
The error log is usually written to a file (typically
+error_log on unix systems and error.log on
+Windows and OS/2). On unix systems it is also possible to have the
+server send errors to the syslog or pipe
+them through a program.
+
+
The format of the error log is relatively free-form and
+descriptive. But there is certain information that is contained
+in most error log entries. For example, here is a typical message.
+
+
+[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test
+
+
+
The first item in the log entry is the date and time of the
+message. The second entry lists the severity of the error being
+reported. The LogLevel directive
+is used to control the types of errors that are sent to the error log
+by restricting the severity level. The third entry gives the IP
+address of the client that generated the error. Beyond that is the
+message itself, which in this case indicates that the server has been
+configured to deny the client access. The server reports the
+file-system path (as opposed to the web path) of the requested
+document.
+
+
A very wide variety of different messages can appear in the error
+log. Most look similar to the example above. The error log will also
+contain debugging output from CGI scripts. Any information written to
+stderr by a CGI script will be copied directly to the
+error log.
+
+
It is not possible to customize the error log by adding or removing
+information. However, error log entries dealing with particular
+requests have corresponding entries in the access
+log. For example, the above example entry corresponds to an
+access log entry with status code 403. Since it is possible to
+customize the access log, you can obtain more information about error
+conditions using that log file.
+
+
During testing, it is often useful to continuously monitor the
+error log for any problems. On unix systems, you can accomplish this
+using:
The server access log records all requests processed by the server.
+The location of the access log as well as its contents are controlled
+by the CustomLog
+directive. The LogFormat directive can
+be used to simplify the selection of the contents of the logs.
+This section describes how to configure the server to record
+information in the access log.
+
+
Of course, storing the information in the access log is only the
+start of log management. The next step is to analyze this information
+to produce useful statistics. Log analysis in general is beyond the
+scope of this document, and not really part of the job of the
+web server itself. For more information about this topic, and for
+applications which perform log analysis, check the Open Directory or Yahoo.
+
+
Various versions of Apache HTTPD have used other modules and
+directives to control access logging, including mod_log_referer,
+mod_log_agent, and the TransferLog directive. The
+CustomLog directive now subsumes the functionality of all
+the older directives.
+
+
The format of the access log is highly configurable. The format is
+specified using a format
+string that looks much like a C-style printf(1) format string.
+Some examples are presented in the next sections. For a complete list
+of the possible contents of the format string, see the mod_log_config documentation.
A typical configuration for the access log might look
+as follows.
+
+
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+CustomLog logs/access_log common
+
+
+
This defines the nicknamecommon and
+associates it with a particular log format string. The format string
+consists of percent directives, each of which tell the server to log a
+particular piece of information. Literal characters may also be
+placed in the format string and will be copied directly into the log
+output. The quote character (") must be escaped by
+placing a back-slash before it to prevent it from being interpreted as
+the end of the format string. The format string may also contain the
+special control characters "\n" for new-line and
+"\t" for tab.
+
+
The CustomLog directive sets up a new log file using
+the defined nickname. The filename for the access log is
+relative to the ServerRoot
+unless it begins with a slash.
+
+
The above configuration will write log entries in a format known as
+the Common Log Format (CLF). This standard format can be produced by
+many different web servers and read by many log analysis programs.
+The log file entries produced in CLF will look something like
+this:
This is the IP
+address of the client (remote host) which made the request to the
+server. If HostNameLookups is set to
+On, then the server will try to determine the hostname
+and log it in place of the IP address. However, this configuration is
+not recommended since it can significantly slow the server. Instead,
+it is best to use a log post-processor such as logresolve to determine the
+hostnames. The IP address reported here is not necessarily the
+address of the machine at which the user is sitting. If a proxy
+server exists between the user and the server, this address will be
+the address of the proxy, rather than the originating machine.
+
+
- (%l)
The "hyphen" in the
+output indicates that the requested piece of information is not
+available. In this case, the information that is not available is the
+RFC 1413 identity of the client determined by identd on
+the clients machine. This information is highly unreliable and should
+almost never be used except on tightly controlled internal networks.
+Apache HTTPD will not even attempt to determine this information
+unless IdentityCheck is set
+to On.
+
+
frank (%u)
This is the userid
+of the person requesting the document as determined by HTTP
+authentication. The same value is typically provided to CGI scripts
+in the REMOTE_USER environment variable. If the status
+code for the request (see below) is 401, then this value should not be
+trusted because the user is not yet authenticated. If the document is
+not password protected, this entry will be "-" just like
+the previous one.
+
+
[10/Oct/2000:13:55:36 -0700] (%t)
+
The time that the server finished processing the request. The
+format is:
+
+It is possible to have the time displayed in another format
+by specifying %{format}t in the log format string, where
+format is as in strftime(3) from the C
+standard library.
+
+
+
"GET /apache_pb.gif HTTP/1.0"
+(\"%r\")
The request line from the client is
+given in double quotes. The request line contains a great deal of
+useful information. First, the method used by the client is
+GET. Second, the client requested the resource
+/apache_pb.gif, and third, the client used the protocol
+HTTP/1.0.
It is also possible to log one or more
+parts of the request line independently. For example, the format
+string "%m %U%q %H" will log the method, path,
+query-string, and protocol, resulting in exactly the same output as
+"%r".
+
+
200
(%>s)
This is the status
+code that the server sends back to the client. This information is
+very valuable, because it reveals whether the request resulted in a
+successful response (codes beginning in 2), a redirection (codes
+beginning in 3), an error caused by the client (codes beginning in 4),
+or an error in the server (codes beginning in 5).
+The full list of possible status codes can be
+found in the HTTP specification (RFC2616 section 10).
+
+
2326 (%b)
+
The last entry indicates the size of the object returned to
+the client, not including the response headers. If no content
+was returned to the client, this value will be "-".
+To log "0" for no content, use %B
+instead.
The "Referer" (sic) HTTP
+request header. This gives the site that the client reports having
+been referred from. (This should be the page that links to or includes
+/apache_pb.gif).
+
+
"Mozilla/4.08 [en] (Win98; I ;Nav)"
+(\"%{User-agent}i\")
The User-Agent HTTP request
+header. This is the identifying information that the client browser
+reports about itself.
Multiple access logs can be created simply by specifying multiple
+CustomLog directives in the configuration file. For
+example, the following directives will create three access logs. The
+first contains the basic CLF information, while the second and third
+contain referer and browser information. The last two
+CustomLog lines show how to mimic the effects of the
+ReferLog and AgentLog directives.
This example also shows that it is not necessary to define a
+nickname with the LogFormat directive. Instead, the log
+format can be specified directly in the CustomLog
+directive.
There are times when it is convenient to exclude certain entries
+from the access logs based on characteristics of the client request.
+This is easily accomplished with the help of environment variables. First, an environment
+variable must be set to indicate that the request meets certain
+conditions. This is usually accomplished with SetEnvIf. Then the
+env= clause of the CustomLog directive is
+used to include or exclude requests where the environment variable is
+set. Some examples:
+
+
+# Mark requests from the loop-back interface
+SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog
+# Mark requests for the robots.txt file
+SetEnvIf Request_URI "^/robots\.txt$" dontlog
+# Log what remains
+CustomLog logs/access_log common env=!dontlog
+
+
+
As another example, consider logging requests from english-speakers
+to one log file, and non-english speakers to a different log file.
+
+
+SetEnvIf Accept-Language "en" english
+CustomLog logs/english_log common env=english
+CustomLog logs/non_english_log common env=!english
+
+
+
Although we have just shown that conditional logging is very
+powerful and flexibly, it is not the only way to control the contents
+of the logs. Log files are more useful when they contain a complete
+record of server activity. It is often easier to simply post-process
+the log files to remove requests that you do not want to consider.
On even a moderately busy server, the quantity of information
+stored in the log files is very large. The access log file typically
+grows 1 MB or more per 10,000 requests. It will consequently be
+necessary to periodically rotate the log files by moving or deleting
+the existing logs. This cannot be done while the server is running,
+because Apache will continue writing to the old log file as long as it
+holds the file open. Instead, the server must be restarted after the log files are moved or
+deleted so that it will open new log files.
+
+
By using a graceful restart, the server can be instructed
+to open new log files without losing any existing or pending
+connections from clients. However, in order to accomplish this, the
+server must continue to write to the old log files while it finishes
+serving old requests. It is therefore necessary to wait for some time
+after the restart before doing any processing on the log files. A
+typical scenario that simply rotates the logs and compresses the old
+logs to save space is:
Apache HTTPD is capable of writing error and access log files
+through a pipe to another process, rather than directly to a file.
+This capability dramatically increases the flexibility of logging,
+without adding code to the main server. In order to write logs to a
+pipe, simply replace the filename with the pipe character
+"|", followed by the name of the executable which should
+accept log entries on its standard input. Apache will start the
+piped-log process when the server starts, and will restart it if it
+crashes while the server is running. (This last feature is why we can
+refer to this technique as "reliable piped logging".)
+
+
Piped log processes are spawned by the parent Apache HTTPD process,
+and inherit the userid of that process. This means that piped log
+programs usually run as root. It is therefore very important to keep
+the programs simple and secure.
+
+
Some simple examples using piped logs:
+
+
+# compressed logs
+CustomLog "|/usr/bin/gzip -c >> /var/log/access_log.gz" common
+# almost-real-time name resolution
+CustomLog "|/usr/local/apache/bin/logresolve >> /var/log/access_log" common
+
+
+
Notice that quotes are used to enclose the entire command
+that will be called for the pipe. Although these examples are
+for the access log, the same technique can be used for the
+error log.
+
+
One important use of piped logs is to allow log rotation without
+having to restart the server. Apache HTTPD includes a simple program
+called rotatelogs for this
+purpose. For example, to rotate the logs every 24 hours, you can
+use:
+
+
+CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
+
+
+
A similar, but much more flexible log rotation program
+called cronolog
+is available at an external site.
+
+
As with conditional logging, piped logs are a very powerful tool,
+but they should not be used where a simpler solution like
+off-line post-processing is available.
When running a server with many virtual
+hosts, there are several options for dealing with log files.
+First, it is possible to use logs exactly as in a single-host server.
+Simply by placing the logging directives outside the
+<VirtualHost> sections in the main server context,
+it is possible to log all requests in the same access log and error
+log. This technique does not allow for easy collection of statistics
+on individual virtual hosts.
+
+
If CustomLog or ErrorLog directives are
+placed inside a <VirtualHost> section, all requests
+or errors for that virtual host will be logged only to the specified
+file. Any virtual host which does not have logging directives will
+still have its requests sent to the main server logs. This technique
+is very useful for a small number of virtual hosts, but if the number
+of hosts is very large, it can be complicated to manage. In addition,
+it can often create problems with insufficient file descriptors.
+
+
For the access log, there is a very good compromise. By adding
+information on the virtual host to the log format string,
+it is possible to log all hosts to the same log, and later
+split the log into individual files. For example, consider the
+following directives.
The %v is used to log the name of the virtual host
+that is serving the request. Then a program like split-logfile can be used to
+post-process the access log in order to split it into one file per
+virtual host.
+
+
Unfortunately, no similar technique is available for the error log,
+so you must choose between mixing all virtual hosts in the same error
+log and using one error log per virtual host.
On startup, Apache HTTPD saves the process id of the parent httpd
+process to the file logs/httpd.pid. This filename can be
+changed with the PidFile
+directive. The process-id is for use by the administrator in
+restarting and terminating the daemon by sending signals
+to the parent process; on Windows, use the -k command line
+option instead. For more information see the Stopping and Restarting page.
+
+
In order to aid in debugging, the
+ScriptLog
+directive allows you to record the input to and output from
+CGI scripts. This should only be used in testing - not for
+live servers. More information is available in the
+mod_cgi documentation.
+
+
When using the powerful and complex features of mod_rewrite, it is almost always
+necessary to use the RewriteLog to help in
+debugging. This log file produces a detailed analysis of how the
+rewriting engine transforms requests. The level of detail is
+controlled by the RewriteLogLevel
+directive.
In order to effectively manage a web server, it is necessary to get
+feedback about the activity and performance of the server as well as
+any problems that may be occuring. The Apache HTTP Server provides
+very comprehensive and flexible logging capabilities. This document
+describes how to configure the various log files, and how to
+understand what the logs contain.
Anyone who can write to the directory where Apache is writing a
+log file can almost certainly gain access to the uid that the server is
+started as, which is normally root. Do NOT give people write
+access to the directory the logs are stored in without being aware of
+the consequences; see the security tips
+document for details.
+
+
In addition, log files may contain information supplied directly
+by the client, without escaping. Therefore, it is possible for
+malicious clients to insert control-characters in the log files, so
+care must be taken in dealing with raw logs.
The server error log, whose name and location is set by the ErrorLog directive, is the most
+important log file. This is the place where Apache HTTPD will send
+diagnostic information and record any errors that it encounters in
+processing requests. It is the first place to look when a problem
+occurs with starting the server or with the operation of the server,
+since it will often contain details of what went wrong and how to fix
+it.
+
+
The error log is usually written to a file (typically
+error_log on unix systems and error.log on
+Windows and OS/2). On unix systems it is also possible to have the
+server send errors to the syslog or pipe
+them through a program.
+
+
The format of the error log is relatively free-form and
+descriptive. But there is certain information that is contained
+in most error log entries. For example, here is a typical message.
+
+
+[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test
+
+
+
The first item in the log entry is the date and time of the
+message. The second entry lists the severity of the error being
+reported. The LogLevel directive
+is used to control the types of errors that are sent to the error log
+by restricting the severity level. The third entry gives the IP
+address of the client that generated the error. Beyond that is the
+message itself, which in this case indicates that the server has been
+configured to deny the client access. The server reports the
+file-system path (as opposed to the web path) of the requested
+document.
+
+
A very wide variety of different messages can appear in the error
+log. Most look similar to the example above. The error log will also
+contain debugging output from CGI scripts. Any information written to
+stderr by a CGI script will be copied directly to the
+error log.
+
+
It is not possible to customize the error log by adding or removing
+information. However, error log entries dealing with particular
+requests have corresponding entries in the access
+log. For example, the above example entry corresponds to an
+access log entry with status code 403. Since it is possible to
+customize the access log, you can obtain more information about error
+conditions using that log file.
+
+
During testing, it is often useful to continuously monitor the
+error log for any problems. On unix systems, you can accomplish this
+using:
The server access log records all requests processed by the server.
+The location of the access log as well as its contents are controlled
+by the CustomLog
+directive. The LogFormat directive can
+be used to simplify the selection of the contents of the logs.
+This section describes how to configure the server to record
+information in the access log.
+
+
Of course, storing the information in the access log is only the
+start of log management. The next step is to analyze this information
+to produce useful statistics. Log analysis in general is beyond the
+scope of this document, and not really part of the job of the
+web server itself. For more information about this topic, and for
+applications which perform log analysis, check the Open Directory or Yahoo.
+
+
Various versions of Apache HTTPD have used other modules and
+directives to control access logging, including mod_log_referer,
+mod_log_agent, and the TransferLog directive. The
+CustomLog directive now subsumes the functionality of all
+the older directives.
+
+
The format of the access log is highly configurable. The format is
+specified using a format
+string that looks much like a C-style printf(1) format string.
+Some examples are presented in the next sections. For a complete list
+of the possible contents of the format string, see the mod_log_config documentation.
A typical configuration for the access log might look
+as follows.
+
+
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+CustomLog logs/access_log common
+
+
+
This defines the nicknamecommon and
+associates it with a particular log format string. The format string
+consists of percent directives, each of which tell the server to log a
+particular piece of information. Literal characters may also be
+placed in the format string and will be copied directly into the log
+output. The quote character (") must be escaped by
+placing a back-slash before it to prevent it from being interpreted as
+the end of the format string. The format string may also contain the
+special control characters "\n" for new-line and
+"\t" for tab.
+
+
The CustomLog directive sets up a new log file using
+the defined nickname. The filename for the access log is
+relative to the ServerRoot
+unless it begins with a slash.
+
+
The above configuration will write log entries in a format known as
+the Common Log Format (CLF). This standard format can be produced by
+many different web servers and read by many log analysis programs.
+The log file entries produced in CLF will look something like
+this:
This is the IP
+address of the client (remote host) which made the request to the
+server. If HostNameLookups is set to
+On, then the server will try to determine the hostname
+and log it in place of the IP address. However, this configuration is
+not recommended since it can significantly slow the server. Instead,
+it is best to use a log post-processor such as logresolve to determine the
+hostnames. The IP address reported here is not necessarily the
+address of the machine at which the user is sitting. If a proxy
+server exists between the user and the server, this address will be
+the address of the proxy, rather than the originating machine.
+
+
- (%l)
The "hyphen" in the
+output indicates that the requested piece of information is not
+available. In this case, the information that is not available is the
+RFC 1413 identity of the client determined by identd on
+the clients machine. This information is highly unreliable and should
+almost never be used except on tightly controlled internal networks.
+Apache HTTPD will not even attempt to determine this information
+unless IdentityCheck is set
+to On.
+
+
frank (%u)
This is the userid
+of the person requesting the document as determined by HTTP
+authentication. The same value is typically provided to CGI scripts
+in the REMOTE_USER environment variable. If the status
+code for the request (see below) is 401, then this value should not be
+trusted because the user is not yet authenticated. If the document is
+not password protected, this entry will be "-" just like
+the previous one.
+
+
[10/Oct/2000:13:55:36 -0700] (%t)
+
The time that the server finished processing the request. The
+format is:
+
+It is possible to have the time displayed in another format
+by specifying %{format}t in the log format string, where
+format is as in strftime(3) from the C
+standard library.
+
+
+
"GET /apache_pb.gif HTTP/1.0"
+(\"%r\")
The request line from the client is
+given in double quotes. The request line contains a great deal of
+useful information. First, the method used by the client is
+GET. Second, the client requested the resource
+/apache_pb.gif, and third, the client used the protocol
+HTTP/1.0.
It is also possible to log one or more
+parts of the request line independently. For example, the format
+string "%m %U%q %H" will log the method, path,
+query-string, and protocol, resulting in exactly the same output as
+"%r".
+
+
200
(%>s)
This is the status
+code that the server sends back to the client. This information is
+very valuable, because it reveals whether the request resulted in a
+successful response (codes beginning in 2), a redirection (codes
+beginning in 3), an error caused by the client (codes beginning in 4),
+or an error in the server (codes beginning in 5).
+The full list of possible status codes can be
+found in the HTTP specification (RFC2616 section 10).
+
+
2326 (%b)
+
The last entry indicates the size of the object returned to
+the client, not including the response headers. If no content
+was returned to the client, this value will be "-".
+To log "0" for no content, use %B
+instead.
The "Referer" (sic) HTTP
+request header. This gives the site that the client reports having
+been referred from. (This should be the page that links to or includes
+/apache_pb.gif).
+
+
"Mozilla/4.08 [en] (Win98; I ;Nav)"
+(\"%{User-agent}i\")
The User-Agent HTTP request
+header. This is the identifying information that the client browser
+reports about itself.
Multiple access logs can be created simply by specifying multiple
+CustomLog directives in the configuration file. For
+example, the following directives will create three access logs. The
+first contains the basic CLF information, while the second and third
+contain referer and browser information. The last two
+CustomLog lines show how to mimic the effects of the
+ReferLog and AgentLog directives.
This example also shows that it is not necessary to define a
+nickname with the LogFormat directive. Instead, the log
+format can be specified directly in the CustomLog
+directive.
There are times when it is convenient to exclude certain entries
+from the access logs based on characteristics of the client request.
+This is easily accomplished with the help of environment variables. First, an environment
+variable must be set to indicate that the request meets certain
+conditions. This is usually accomplished with SetEnvIf. Then the
+env= clause of the CustomLog directive is
+used to include or exclude requests where the environment variable is
+set. Some examples:
+
+
+# Mark requests from the loop-back interface
+SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog
+# Mark requests for the robots.txt file
+SetEnvIf Request_URI "^/robots\.txt$" dontlog
+# Log what remains
+CustomLog logs/access_log common env=!dontlog
+
+
+
As another example, consider logging requests from english-speakers
+to one log file, and non-english speakers to a different log file.
+
+
+SetEnvIf Accept-Language "en" english
+CustomLog logs/english_log common env=english
+CustomLog logs/non_english_log common env=!english
+
+
+
Although we have just shown that conditional logging is very
+powerful and flexibly, it is not the only way to control the contents
+of the logs. Log files are more useful when they contain a complete
+record of server activity. It is often easier to simply post-process
+the log files to remove requests that you do not want to consider.
On even a moderately busy server, the quantity of information
+stored in the log files is very large. The access log file typically
+grows 1 MB or more per 10,000 requests. It will consequently be
+necessary to periodically rotate the log files by moving or deleting
+the existing logs. This cannot be done while the server is running,
+because Apache will continue writing to the old log file as long as it
+holds the file open. Instead, the server must be restarted after the log files are moved or
+deleted so that it will open new log files.
+
+
By using a graceful restart, the server can be instructed
+to open new log files without losing any existing or pending
+connections from clients. However, in order to accomplish this, the
+server must continue to write to the old log files while it finishes
+serving old requests. It is therefore necessary to wait for some time
+after the restart before doing any processing on the log files. A
+typical scenario that simply rotates the logs and compresses the old
+logs to save space is:
Apache HTTPD is capable of writing error and access log files
+through a pipe to another process, rather than directly to a file.
+This capability dramatically increases the flexibility of logging,
+without adding code to the main server. In order to write logs to a
+pipe, simply replace the filename with the pipe character
+"|", followed by the name of the executable which should
+accept log entries on its standard input. Apache will start the
+piped-log process when the server starts, and will restart it if it
+crashes while the server is running. (This last feature is why we can
+refer to this technique as "reliable piped logging".)
+
+
Piped log processes are spawned by the parent Apache HTTPD process,
+and inherit the userid of that process. This means that piped log
+programs usually run as root. It is therefore very important to keep
+the programs simple and secure.
+
+
Some simple examples using piped logs:
+
+
+# compressed logs
+CustomLog "|/usr/bin/gzip -c >> /var/log/access_log.gz" common
+# almost-real-time name resolution
+CustomLog "|/usr/local/apache/bin/logresolve >> /var/log/access_log" common
+
+
+
Notice that quotes are used to enclose the entire command
+that will be called for the pipe. Although these examples are
+for the access log, the same technique can be used for the
+error log.
+
+
One important use of piped logs is to allow log rotation without
+having to restart the server. Apache HTTPD includes a simple program
+called rotatelogs for this
+purpose. For example, to rotate the logs every 24 hours, you can
+use:
+
+
+CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common
+
+
+
A similar, but much more flexible log rotation program
+called cronolog
+is available at an external site.
+
+
As with conditional logging, piped logs are a very powerful tool,
+but they should not be used where a simpler solution like
+off-line post-processing is available.
When running a server with many virtual
+hosts, there are several options for dealing with log files.
+First, it is possible to use logs exactly as in a single-host server.
+Simply by placing the logging directives outside the
+<VirtualHost> sections in the main server context,
+it is possible to log all requests in the same access log and error
+log. This technique does not allow for easy collection of statistics
+on individual virtual hosts.
+
+
If CustomLog or ErrorLog directives are
+placed inside a <VirtualHost> section, all requests
+or errors for that virtual host will be logged only to the specified
+file. Any virtual host which does not have logging directives will
+still have its requests sent to the main server logs. This technique
+is very useful for a small number of virtual hosts, but if the number
+of hosts is very large, it can be complicated to manage. In addition,
+it can often create problems with insufficient file descriptors.
+
+
For the access log, there is a very good compromise. By adding
+information on the virtual host to the log format string,
+it is possible to log all hosts to the same log, and later
+split the log into individual files. For example, consider the
+following directives.
The %v is used to log the name of the virtual host
+that is serving the request. Then a program like split-logfile can be used to
+post-process the access log in order to split it into one file per
+virtual host.
+
+
Unfortunately, no similar technique is available for the error log,
+so you must choose between mixing all virtual hosts in the same error
+log and using one error log per virtual host.
On startup, Apache HTTPD saves the process id of the parent httpd
+process to the file logs/httpd.pid. This filename can be
+changed with the PidFile
+directive. The process-id is for use by the administrator in
+restarting and terminating the daemon by sending signals
+to the parent process; on Windows, use the -k command line
+option instead. For more information see the Stopping and Restarting page.
+
+
In order to aid in debugging, the
+ScriptLog
+directive allows you to record the input to and output from
+CGI scripts. This should only be used in testing - not for
+live servers. More information is available in the
+mod_cgi documentation.
+
+
When using the powerful and complex features of mod_rewrite, it is almost always
+necessary to use the RewriteLog to help in
+debugging. This log file produces a detailed analysis of how the
+rewriting engine transforms requests. The level of detail is
+controlled by the RewriteLogLevel
+directive.
On certain unix operating systems, forking a process from a
+multi-threaded server is a very expensive operation because the new
+process will replicate all the threads of the parent process. In
+order to avoid incurring this expense on each CGI invocation, mod_cgid
+creates an external daemon that is responsible for forking child
+processes to run CGI scripts. The main server communicates with this
+daemon using a unix domain socket.
+
+
This module is used by default whenever a multi-threaded MPM is
+selected during the compilation process. At the user level, this
+module is identical in configuration and operation to mod_cgi. The only exception is the additional
+directive ScriptSock which gives the name of the socket
+to use for communication with the cgi daemon.
This directive sets the name of the socket to use for communication
+with the CGI daemon. The socket will be opened using the permissions
+of the user who starts Apache (usually root). To maintain the security
+of communications with CGI scripts, it is important that no other
+user has permission to write in the directory where the socket is
+located.
+The SuexecUserGroup directive allows you to specify a user and
+group for CGI programs to run as. Non-CGI requests are still processes
+with the user specified in the User directive. This directive replaces
+using the User and Group directives inside of VirtualHosts.
+
+
+
+
+ Apache HTTP Server Version 2.0
+
+
+
+
+
+
+
diff --git a/include/util_ldap.h b/include/util_ldap.h
new file mode 100644
index 00000000000..10dc2eabe55
--- /dev/null
+++ b/include/util_ldap.h
@@ -0,0 +1,275 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+#ifndef UTIL_LDAP_H
+#define UTIL_LDAP_H
+
+#include
+
+/* this whole thing disappears if LDAP is not enabled */
+#ifdef APU_HAS_LDAP
+
+/* APR header files */
+#include
+#include
+#include
+
+/* Apache header files */
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+
+
+/*
+ * LDAP Connections
+ */
+
+/* Values that the deref member can have */
+typedef enum {
+ never=LDAP_DEREF_NEVER,
+ searching=LDAP_DEREF_SEARCHING,
+ finding=LDAP_DEREF_FINDING,
+ always=LDAP_DEREF_ALWAYS
+} deref_options;
+
+/* Structure representing an LDAP connection */
+typedef struct util_ldap_connection_t {
+ LDAP *ldap;
+ apr_lock_t *lock; /* Lock to indicate this connection is in use */
+ int bound; /* Flag to indicate whether this connection is bound yet */
+
+ const char *host; /* Name of the LDAP server (or space separated list) */
+ int port; /* Port of the LDAP server */
+ deref_options deref; /* how to handle alias dereferening */
+
+ const char *binddn; /* DN to bind to server (can be NULL) */
+ const char *bindpw; /* Password to bind to server (can be NULL) */
+
+ int netscapessl; /* True if use Netscape SSL connection */
+ const char *certtdb; /* Path to Netscape CA database */
+
+ int starttls; /* True if StartTLS is enabled */
+ int withtls; /* True if StartTLS on this connection */
+
+ const char *reason; /* Reason for an error failure */
+
+ struct util_ldap_connection_t *next;
+} util_ldap_connection_t;
+
+/* LDAP cache state information */
+typedef struct util_ldap_state_t {
+ apr_pool_t *pool; /* pool from which this state is allocated */
+ apr_lock_t *mutex; /* mutex lock for the connection list */
+
+ apr_size_t cache_bytes; /* Size (in bytes) of shared memory cache */
+ long search_cache_ttl; /* TTL for search cache */
+ long search_cache_size; /* Size (in entries) of search cache */
+ long compare_cache_ttl; /* TTL for compare cache */
+ long compare_cache_size; /* Size (in entries) of compare cache */
+
+ struct util_ldap_connection_t *connections;
+#ifdef APU_HAS_LDAP_NETSCAPE_SSL
+ int have_certdb;
+#endif
+} util_ldap_state_t;
+
+
+/**
+ * Open a connection to an LDAP server
+ * @param ldc A structure containing the expanded details of the server
+ * to connect to. The handle to the LDAP connection is returned
+ * as ldc->ldap.
+ * @tip This function connects to the LDAP server and binds. It does not
+ * connect if already connected (ldc->ldap != NULL). Does not bind
+ * if already bound.
+ * @return If successful LDAP_SUCCESS is returned.
+ * @deffunc int util_ldap_connection_open(util_ldap_connection_t *ldc)
+ */
+int util_ldap_connection_open(util_ldap_connection_t *ldc);
+
+/**
+ * Close a connection to an LDAP server
+ * @param ldc A structure containing the expanded details of the server
+ that was connected.
+ * @tip This function unbinds from the LDAP server, and clears ldc->ldap.
+ * It is possible to rebind to this server again using the same ldc
+ * structure, using apr_ldap_open_connection().
+ * @deffunc util_ldap_close_connection(util_ldap_connection_t *ldc)
+ */
+void util_ldap_connection_close(util_ldap_connection_t *ldc);
+
+/**
+ * Find a connection in a list of connections
+ * @param r The request record
+ * @param host The hostname to connect to (multiple hosts space separated)
+ * @param port The port to connect to
+ * @param binddn The DN to bind with
+ * @param bindpw The password to bind with
+ * @param deref The dereferencing behavior
+ * @param netscapessl Start SSL on the connection using ldapssl_client_init() [0|1]
+ * @param starttls Start TLS using STARTTLS parameter [0|1]
+ * @tip Once a connection is found and returned, a lock will be acquired to
+ * lock that particular connection, so that another thread does not try and
+ * use this connection while it is busy. Once you are finished with a connection,
+ * apr_ldap_connection_close() must be called to release this connection.
+ * @deffunc util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
+ * const char *binddn, const char *bindpw, deref_options deref,
+ * int netscapessl, int starttls)
+ */
+util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
+ const char *binddn, const char *bindpw, deref_options deref,
+ int netscapessl, int starttls);
+
+
+/**
+ * Compare two DNs for sameness
+ * @param r The request record
+ * @param ldc The LDAP connection being used.
+ * @param url The URL of the LDAP connection - used for deciding which cache to use.
+ * @param dn The first DN to compare.
+ * @param reqdn The DN to compare the first DN to.
+ * @param compare_dn_on_server Flag to determine whether the DNs should be checked using
+ * LDAP calls or with a direct string comparision. A direct
+ * string comparison is faster, but not as accurate - false
+ * negative comparisons are possible.
+ * @tip Two DNs can be equal and still fail a string comparison. Eg "dc=example,dc=com"
+ * and "dc=example, dc=com". Use the compare_dn_on_server unless there are serious
+ * performance issues.
+ * @deffunc int util_ldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
+ * const char *url, const char *dn, const char *reqdn,
+ * int compare_dn_on_server)
+ */
+int util_ldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
+ const char *url, const char *dn, const char *reqdn,
+ int compare_dn_on_server);
+
+/**
+ * A generic LDAP compare function
+ * @param r The request record
+ * @param ldc The LDAP connection being used.
+ * @param url The URL of the LDAP connection - used for deciding which cache to use.
+ * @param dn The DN of the object in which we do the compare.
+ * @param attrib The attribute within the object we are comparing for.
+ * @param value The value of the attribute we are trying to compare for.
+ * @tip Use this function to determine whether an attribute/value pair exists within an
+ * object. Typically this would be used to determine LDAP group membership.
+ * @deffunc int util_ldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
+ * const char *url, const char *dn, const char *attrib, const char *value)
+ */
+int util_ldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
+ const char *url, const char *dn, const char *attrib, const char *value);
+
+/**
+ * Checks a username/password combination by binding to the LDAP server
+ * @param r The request record
+ * @param ldc The LDAP connection being used.
+ * @param url The URL of the LDAP connection - used for deciding which cache to use.
+ * @param basedn The Base DN to search for the user in.
+ * @param scope LDAP scope of the search.
+ * @param filter The user to search for in the form of an LDAP filter. This filter must return
+ * exactly one user for the check to be successful.
+ * @param bindpw The user password to bind as.
+ * @param binddn The DN of the user will be returned in this variable.
+ * @tip The filter supplied will be searched for. If a single entry is returned, an attempt
+ * is made to bind as that user. If this bind succeeds, the user is not validated.
+ * @deffunc int util_ldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
+ * char *url, const char *basedn, int scope,
+ * char *filter, char *bindpw, char **binddn)
+ */
+int util_ldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
+ const char *url, const char *basedn, int scope,
+ const char *filter, const char *bindpw, const char **binddn);
+
+/* from apr_ldap_cache.c */
+
+/**
+ * Init the LDAP cache
+ * @param pool The pool to use to initialise the cache
+ * @param reqsize The size of the shared memory segement to request. A size
+ * of zero requests the max size possible from
+ * apr_shmem_init()
+ * @deffunc void util_ldap_cache_init(apr_pool_t *p)
+ * @return The status code returned is the status code of the
+ * apr_smmem_init() call. Regardless of the status, the cache
+ * will be set up at least for in-process or in-thread operation.
+ */
+apr_status_t util_ldap_cache_init(apr_pool_t *pool, apr_size_t reqsize);
+
+/**
+ * Display formatted stats for cache
+ * @param The pool to allocate the returned string from
+ * @tip This function returns a string allocated from the provided pool that describes
+ * various stats about the cache.
+ * @deffunc char *util_ald_cache_display(apr_pool_t *pool)
+ */
+char *util_ald_cache_display(apr_pool_t *pool);
+
+
+/* from apr_ldap_cache_mgr.c */
+
+/**
+ * Display formatted stats for cache
+ * @param The pool to allocate the returned string from
+ * @tip This function returns a string allocated from the provided pool that describes
+ * various stats about the cache.
+ * @deffunc char *util_ald_cache_display(apr_pool_t *pool)
+ */
+char *util_ald_cache_display(apr_pool_t *pool);
+
+#endif /* APU_HAS_LDAP */
+#endif /* UTIL_LDAP_H */
diff --git a/include/util_time.h b/include/util_time.h
new file mode 100644
index 00000000000..704d0e02d55
--- /dev/null
+++ b/include/util_time.h
@@ -0,0 +1,111 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+#ifndef APACHE_UTIL_TIME_H
+#define APACHE_UTIL_TIME_H
+
+#include "apr.h"
+#include "apr_time.h"
+#include "httpd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @package Apache date/time handling functions
+ */
+
+/* Maximum delta from the current time, in seconds, for a past time
+ * to qualify as "recent" for use in the ap_explode_recent_*() functions:
+ */
+#define AP_TIME_RECENT_THRESHOLD 15
+
+/**
+ * convert a recent time to its human readable components in local timezone
+ * @param tm the exploded time
+ * @param t the time to explode: MUST be within the last
+ * AP_TIME_RECENT_THRESHOLD seconds
+ * @note This is a faster alternative to apr_explode_localtime that uses
+ * a cache of pre-exploded time structures. It is useful for things
+ * that need to explode the current time multiple times per second,
+ * like loggers.
+ * @return APR_SUCCESS iff successful
+ * @deffunc apr_status_t ap_explode_recent_localtime(apr_exploded_time_t *tm, apr_time_t t);
+ */
+AP_DECLARE(apr_status_t) ap_explode_recent_localtime(apr_exploded_time_t *tm,
+ apr_time_t t);
+
+/**
+ * convert a recent time to its human readable components in GMT timezone
+ * @param tm the exploded time
+ * @param t the time to explode: MUST be within the last
+ * AP_TIME_RECENT_THRESHOLD seconds
+ * @note This is a faster alternative to apr_explode_gmt that uses
+ * a cache of pre-exploded time structures. It is useful for things
+ * that need to explode the current time multiple times per second,
+ * like loggers.
+ * @return APR_SUCCESS iff successful
+ * @deffunc apr_status_t ap_explode_recent_gmt(apr_exploded_time_t *tm, apr_time_t t);
+ */
+AP_DECLARE(apr_status_t) ap_explode_recent_gmt(apr_exploded_time_t *tm,
+ apr_time_t t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !APACHE_UTIL_TIME_H */
diff --git a/modules/experimental/cache_storage.c b/modules/experimental/cache_storage.c
new file mode 100644
index 00000000000..050628dad1e
--- /dev/null
+++ b/modules/experimental/cache_storage.c
@@ -0,0 +1,276 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_cache.h"
+
+APR_HOOK_STRUCT(
+ APR_HOOK_LINK(remove_url)
+ APR_HOOK_LINK(create_entity)
+ APR_HOOK_LINK(open_entity)
+)
+
+module AP_MODULE_DECLARE_DATA tcache_module;
+
+/* -------------------------------------------------------------- */
+
+/*
+ * delete all URL entities from the cache
+ *
+ */
+int cache_remove_url(request_rec *r, const char *types, char *url)
+{
+ const char *next = types;
+ const char *type;
+
+ /* for each specified cache type, delete the URL */
+ while ((type = ap_cache_tokstr(r->pool, next, &next))) {
+ cache_run_remove_url(type, url);
+ }
+ return OK;
+}
+
+
+/*
+ * create a new URL entity in the cache
+ *
+ * It is possible to store more than once entity per URL. This
+ * function will always create a new entity, regardless of whether
+ * other entities already exist for the same URL.
+ *
+ * The size of the entity is provided so that a cache module can
+ * decide whether or not it wants to cache this particular entity.
+ * If the size is unknown, a size of -1 should be set.
+ */
+int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size)
+{
+ cache_handle *h;
+ const char *next = types;
+ const char *type;
+ apr_status_t rv;
+ cache_request_rec *cache = (cache_request_rec *) ap_get_module_config(r->request_config,
+ &tcache_module);
+
+ /* for each specified cache type, delete the URL */
+ while (next) {
+ type = ap_cache_tokstr(r->pool, next, &next);
+ switch (rv = cache_run_create_entity(&h, type, url, size)) {
+ case OK: {
+ cache->handle = h;
+ return OK;
+ }
+ case DECLINED: {
+ continue;
+ }
+ default: {
+ return rv;
+ }
+ }
+ }
+ return DECLINED;
+}
+
+/*
+ * remove a specific URL entity from the cache
+ *
+ * The specific entity referenced by the cache_handle is removed
+ * from the cache, and the cache_handle is closed.
+ */
+int cache_remove_entity(request_rec *r, const char *types, cache_handle *h)
+{
+ const char *next = types;
+ const char *type;
+
+ while (next) {
+ type = ap_cache_tokstr(r->pool, next, &next);
+ }
+ return 1;
+}
+
+/*
+ * select a specific URL entity in the cache
+ *
+ * It is possible to store more than one entity per URL. Content
+ * negotiation is used to select an entity. Once an entity is
+ * selected, details of it are stored in the per request
+ * config to save time when serving the request later.
+ *
+ * This function returns OK if successful, DECLINED if no
+ * cached entity fits the bill.
+ */
+int cache_select_url(request_rec *r, const char *types, char *url)
+{
+ cache_handle *h;
+ const char *next = types;
+ const char *type;
+ apr_status_t rv;
+ cache_request_rec *cache = (cache_request_rec *) ap_get_module_config(r->request_config,
+ &tcache_module);
+
+ /* go through the cache types till we get a match */
+ while (next) {
+ type = ap_cache_tokstr(r->pool, next, &next);
+ switch ((rv = cache_run_open_entity(&h, type, url))) {
+ case OK: {
+ /* cool bananas! */
+ cache->handle = h;
+/*** loop through returned entities */
+/*** do freshness calculation here */
+ cache->fresh = 1;
+/*** do content negotiation here */
+ return OK;
+ }
+ case DECLINED: {
+ /* try again with next cache type */
+ continue;
+ }
+ default: {
+ /* oo-er! an error */
+ return rv;
+ }
+ }
+ }
+ return DECLINED;
+}
+
+apr_status_t cache_write_entity_headers(cache_handle *h, request_rec *r, cache_info *info,
+ apr_table_t *headers_in, apr_table_t *headers_out)
+{
+ const char *ct;
+
+ ct = ap_table_get(r->headers_out, "Content-Type");
+ info->content_type = ct;
+ h->write_headers(h, r, info);
+ return APR_SUCCESS;
+}
+apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *b)
+{
+ apr_status_t rv = APR_SUCCESS;
+ if (h->write_body(h, b) != OK) {
+ }
+ return rv;
+}
+
+apr_status_t cache_read_entity_headers(cache_handle *h, request_rec *r,
+ apr_table_t **headers)
+{
+ cache_info *info;
+
+ /* Be careful to not modify info. */
+ h->read_headers(h, r, &info);
+
+ /* Build the header table from info in the info struct */
+ *headers = apr_table_make(r->pool, 15);
+ /* Content-Length */
+ if (info->len)
+ apr_table_set(*headers, "Content-Length", apr_psprintf(r->pool, "%lu", info->len));
+
+ /* Last-Modified */
+ if (info->lastmod) {
+ }
+ /* Expires */
+ if (info->expire) {
+ }
+ if (info->content_type) {
+ r->content_type = apr_pstrdup(r->pool, info->content_type);
+ }
+ /* Date */
+
+ return APR_SUCCESS;
+}
+apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *b)
+{
+ h->read_body(h, b);
+ return APR_SUCCESS;
+}
+
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity,
+ (cache_handle **hp, const char *type,
+ char *url, apr_size_t len),(hp,type,url,len),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity,
+ (cache_handle **hp, const char *type,
+ char *url),(hp,type,url),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url,
+ (const char *type, char *url),(type,url),OK,DECLINED)
+#if 0
+/* BillS doesn't think these should be hooks.
+ * All functions which accept a cache_handle * argument should use
+ * function pointers in the cache_handle. Leave them here for now as
+ * points for discussion...
+ */
+
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, remove_entity,
+ (cache_handle *h),(h),DECLINED)
+
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, read_entity_headers,
+ (cache_handle *h, request_rec *r,
+ apr_table_t **headers),
+ (h,info,headers_in,headers_out),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, read_entity_body,
+ (cache_handle *h,
+ apr_bucket_brigade *out),(h,out),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, write_entity_headers,
+ (cache_handle *h, cache_info *info,
+ apr_table_t *headers_in,
+ apr_table_t *headers_out),
+ (h,info,headers_in,headers_out),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, write_entity_body,
+ (cache_handle *h,
+ apr_bucket_brigade *in),(h,in),DECLINED)
+#endif
diff --git a/modules/experimental/cache_util.c b/modules/experimental/cache_util.c
new file mode 100644
index 00000000000..cc37aa972c6
--- /dev/null
+++ b/modules/experimental/cache_util.c
@@ -0,0 +1,206 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_cache.h"
+
+
+
+/* -------------------------------------------------------------- */
+
+/* return true if the request is conditional */
+int ap_cache_request_is_conditional(request_rec *r)
+{
+ if (apr_table_get(r->headers_in, "If-Match") ||
+ apr_table_get(r->headers_in, "If-None-Match") ||
+ apr_table_get(r->headers_in, "If-Modified-Since") ||
+ apr_table_get(r->headers_in, "If-Unmodified-Since")) {
+
+ return 1;
+ }
+ return 0;
+}
+
+
+/* remove other filters from filter stack */
+void ap_cache_reset_output_filters(request_rec *r)
+{
+ ap_filter_t *f = r->output_filters;
+
+ while (f) {
+ if (!strcasecmp(f->frec->name, "CORE") ||
+ !strcasecmp(f->frec->name, "CONTENT_LENGTH") ||
+ !strcasecmp(f->frec->name, "HTTP_HEADER")) {
+ f = f->next;
+ continue;
+ }
+ else {
+ ap_remove_output_filter(f);
+ f = f->next;
+ }
+ }
+}
+
+const char *ap_cache_get_cachetype(request_rec *r, cache_server_conf *conf, const char *url)
+{
+ const char *type = NULL;
+ int i;
+
+ /* loop through all the cacheenable entries */
+ for (i = 0; i < conf->cacheenable->nelts; i++) {
+ struct cache_enable *ent = (struct cache_enable *) conf->cacheenable->elts;
+ const char *thisurl = ent[i].url;
+ const char *thistype = ent[i].type;
+ if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
+ if (!type) {
+ type = thistype;
+ }
+ else {
+ type = apr_pstrcat(r->pool, type, ",", thistype, NULL);
+ }
+ }
+ }
+
+ /* then loop through all the cachedisable entries */
+ for (i = 0; i < conf->cachedisable->nelts; i++) {
+ struct cache_disable *ent = (struct cache_disable *) conf->cachedisable->elts;
+ const char *thisurl = ent[i].url;
+ if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
+ type = NULL;
+ }
+ }
+
+ return type;
+}
+
+/*
+ * list is a comma-separated list of case-insensitive tokens, with
+ * optional whitespace around the tokens.
+ * The return returns 1 if the token val is found in the list, or 0
+ * otherwise.
+ */
+int ap_cache_liststr(const char *list, const char *key, char **val)
+{
+ int len, i;
+ char *p;
+ char valbuf[HUGE_STRING_LEN];
+ valbuf[sizeof(valbuf)-1] = 0; /* safety terminating zero */
+
+ len = strlen(key);
+
+ while (list != NULL) {
+ p = strchr((char *) list, ',');
+ if (p != NULL) {
+ i = p - list;
+ do
+ p++;
+ while (ap_isspace(*p));
+ }
+ else
+ i = strlen(list);
+
+ while (i > 0 && ap_isspace(list[i - 1]))
+ i--;
+ if (i == len && strncasecmp(list, key, len) == 0) {
+ if (val) {
+ p = strchr((char *) list, ',');
+ while (ap_isspace(*list)) {
+ list++;
+ }
+ if ('=' == list[0])
+ list++;
+ while (ap_isspace(*list)) {
+ list++;
+ }
+ strncpy(valbuf, list, MIN(p-list, sizeof(valbuf)-1));
+ *val = valbuf;
+ }
+ return 1;
+ }
+ list = p;
+ }
+ return 0;
+}
+
+/* return each comma separated token, one at a time */
+const char *ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str)
+{
+ apr_off_t len, i;
+ const char *s;
+
+ s = ap_strchr_c(list, ',');
+ if (s != NULL) {
+ i = s - list;
+ do
+ s++;
+ while (apr_isspace(*s));
+ }
+ else
+ i = strlen(list);
+
+ while (i > 0 && apr_isspace(list[i - 1]))
+ i--;
+
+ *str = s;
+ if (len)
+ return apr_pstrndup(p, list, len);
+ else
+ return NULL;
+
+}
diff --git a/modules/experimental/mod_auth_ldap.c b/modules/experimental/mod_auth_ldap.c
new file mode 100644
index 00000000000..6be891cf172
--- /dev/null
+++ b/modules/experimental/mod_auth_ldap.c
@@ -0,0 +1,862 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+/*
+ * mod_auth_ldap.c: LDAP authentication module
+ *
+ * Original code from auth_ldap module for Apache v1.3:
+ * Copyright 1998, 1999 Enbridge Pipelines Inc.
+ * Copyright 1999-2001 Dave Carrigan
+ */
+
+#include
+#include
+
+#include "ap_config.h"
+#if APR_HAVE_UNISTD_H
+/* for getpid() */
+#include
+#endif
+#include
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "util_ldap.h"
+
+/* per directory configuration */
+typedef struct {
+ apr_pool_t *pool; /* Pool that this config is allocated from */
+ apr_lock_t *lock; /* Lock for this config */
+ int auth_authoritative; /* Is this auth method the one and only? */
+ int enabled; /* Is auth_ldap enabled in this directory? */
+
+ /* These parameters are all derived from the AuthLDAPURL directive */
+ char *url; /* String representation of the URL */
+
+ char *host; /* Name of the LDAP server (or space separated list) */
+ int port; /* Port of the LDAP server */
+ char *basedn; /* Base DN to do all searches from */
+ char *attribute; /* Attribute to search for */
+ char **attributes; /* Array of all the attributes to return */
+ int scope; /* Scope of the search */
+ char *filter; /* Filter to further limit the search */
+ deref_options deref; /* how to handle alias dereferening */
+ char *binddn; /* DN to bind to server (can be NULL) */
+ char *bindpw; /* Password to bind to server (can be NULL) */
+
+ int frontpage_hack; /* Hack for frontpage support */
+ int user_is_dn; /* If true, connection->user is DN instead of userid */
+ int compare_dn_on_server; /* If true, will use server to do DN compare */
+
+ int have_ldap_url; /* Set if we have found an LDAP url */
+
+ apr_array_header_t *groupattr; /* List of Group attributes */
+ int group_attrib_is_dn; /* If true, the group attribute is the DN, otherwise,
+ it's the exact string passed by the HTTP client */
+
+ int netscapessl; /* True if Netscape SSL is enabled */
+ int starttls; /* True if StartTLS is enabled */
+} mod_auth_ldap_config_t;
+
+typedef struct mod_auth_ldap_request_t {
+ char *dn; /* The saved dn from a successful search */
+ char *user; /* The username provided by the client */
+} mod_auth_ldap_request_t;
+
+/* maximum group elements supported */
+#define GROUPATTR_MAX_ELTS 10
+
+struct mod_auth_ldap_groupattr_entry_t {
+ char *name;
+};
+
+module AP_MODULE_DECLARE_DATA auth_ldap_module;
+
+/* function prototypes */
+void mod_auth_ldap_build_filter(char *filtbuf,
+ request_rec *r,
+ mod_auth_ldap_config_t *sec);
+int mod_auth_ldap_check_user_id(request_rec *r);
+int mod_auth_ldap_auth_checker(request_rec *r);
+void *mod_auth_ldap_create_dir_config(apr_pool_t *p, char *d);
+
+/* ---------------------------------------- */
+
+
+/*
+ * Build the search filter, or at least as much of the search filter that
+ * will fit in the buffer. We don't worry about the buffer not being able
+ * to hold the entire filter. If the buffer wasn't big enough to hold the
+ * filter, ldap_search_s will complain, but the only situation where this
+ * is likely to happen is if the client sent a really, really long
+ * username, most likely as part of an attack.
+ *
+ * The search filter consists of the filter provided with the URL,
+ * combined with a filter made up of the attribute provided with the URL,
+ * and the actual username passed by the HTTP client. For example, assume
+ * that the LDAP URL is
+ *
+ * ldap://ldap.airius.com/ou=People, o=Airius?uid??(posixid=*)
+ *
+ * Further, assume that the userid passed by the client was `userj'. The
+ * search filter will be (&(posixid=*)(uid=userj)).
+ */
+#define FILTER_LENGTH MAX_STRING_LEN
+void mod_auth_ldap_build_filter(char *filtbuf,
+ request_rec *r,
+ mod_auth_ldap_config_t *sec)
+{
+ char *p, *q, *filtbuf_end;
+ /*
+ * Create the first part of the filter, which consists of the
+ * config-supplied portions.
+ */
+ apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", sec->filter, sec->attribute);
+
+ /*
+ * Now add the client-supplied username to the filter, ensuring that any
+ * LDAP filter metachars are escaped.
+ */
+ filtbuf_end = filtbuf + FILTER_LENGTH - 1;
+ for (p = r->user, q=filtbuf + strlen(filtbuf);
+ *p && q < filtbuf_end; *q++ = *p++) {
+ if (strchr("*()\\", *p) != NULL) {
+ *q++ = '\\';
+ if (q >= filtbuf_end) {
+ break;
+ }
+ }
+ }
+ *q = '\0';
+
+ /*
+ * Append the closing parens of the filter, unless doing so would
+ * overrun the buffer.
+ */
+ if (q + 2 <= filtbuf_end)
+ strcat(filtbuf, "))");
+}
+
+
+/*
+ * Authentication Phase
+ * --------------------
+ *
+ * This phase authenticates the credentials the user has sent with
+ * the request (ie the username and password are checked). This is done
+ * by making an attempt to bind to the LDAP server using this user's
+ * DN and the supplied password.
+ *
+ */
+int mod_auth_ldap_check_user_id(request_rec *r)
+{
+ const char **vals = NULL;
+ char filtbuf[FILTER_LENGTH];
+ mod_auth_ldap_config_t *sec =
+ (mod_auth_ldap_config_t *)ap_get_module_config(r->per_dir_config, &auth_ldap_module);
+
+ util_ldap_connection_t *ldc = NULL;
+ const char *sent_pw;
+ int result = 0;
+ const char *dn = NULL;
+
+ mod_auth_ldap_request_t *req =
+ (mod_auth_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_auth_ldap_request_t));
+ ap_set_module_config(r->request_config, &auth_ldap_module, req);
+
+ if (!sec->enabled) {
+ return DECLINED;
+ }
+
+ /*
+ * Basic sanity checks before any LDAP operations even happen.
+ */
+ if (!sec->have_ldap_url) {
+ return DECLINED;
+ }
+
+ /* There is a good AuthLDAPURL, right? */
+ if (sec->host) {
+ ldc = util_ldap_connection_find(r, sec->host, sec->port,
+ sec->binddn, sec->bindpw, sec->deref,
+ sec->netscapessl, sec->starttls);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authenticate: no sec->host - weird...?", getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authenticate: using URL %s", getpid(), sec->url);
+
+ /* Get the password that the client sent */
+ if ((result = ap_get_basic_auth_pw(r, &sent_pw))) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authenticate: "
+ "ap_get_basic_auth_pw() returns %d", getpid(), result);
+ util_ldap_connection_close(ldc);
+ return result;
+ }
+
+ /* build the username filter */
+ mod_auth_ldap_build_filter(filtbuf, r, sec);
+
+ /* do the user search */
+ result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope,
+ sec->attributes, filtbuf, sent_pw, &dn, &vals);
+ util_ldap_connection_close(ldc);
+
+ if (result != LDAP_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authenticate: "
+ "user %s authentication failed; URI %s [%s][%s]",
+ getpid(), r->user, r->uri, ldc->reason, ldap_err2string(result));
+ if (LDAP_INVALID_CREDENTIALS == result) {
+ ap_note_basic_auth_failure(r);
+ return HTTP_UNAUTHORIZED;
+ }
+ else {
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED: DECLINED;
+ }
+ }
+
+ /* mark the user and DN */
+ req->dn = apr_pstrdup(r->pool, dn);
+ req->user = r->user;
+ if (sec->user_is_dn) {
+ r->user = req->dn;
+ }
+
+ /* add environment variables */
+ if (sec->attributes && vals) {
+ apr_table_t *e = r->subprocess_env;
+ int i = 0;
+ while (sec->attributes[i]) {
+ char *str = apr_pstrcat(r->pool, "AUTHENTICATE_", sec->attributes[i], NULL);
+ int j = 13;
+ while (str[j]) {
+ if (str[j] >= 'a' && str[j] <= 'z') {
+ str[j] = str[j] - ('a' - 'A');
+ }
+ j++;
+ }
+ apr_table_setn(e, str, vals[i]);
+ i++;
+ }
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authenticate: accepting %s", getpid(), r->user);
+
+ return OK;
+}
+
+
+/*
+ * Authorisation Phase
+ * -------------------
+ *
+ * After checking whether the username and password are correct, we need
+ * to check whether that user is authorised to view this resource. The
+ * require directive is used to do this:
+ *
+ * require valid-user Any authenticated is allowed in.
+ * require user This particular user is allowed in.
+ * require group The user must be a member of this group
+ * in order to be allowed in.
+ * require dn The user must have the following DN in the
+ * LDAP tree to be let in.
+ *
+ */
+int mod_auth_ldap_auth_checker(request_rec *r)
+{
+ int result = 0;
+ mod_auth_ldap_request_t *req =
+ (mod_auth_ldap_request_t *)ap_get_module_config(r->request_config,
+ &auth_ldap_module);
+ mod_auth_ldap_config_t *sec =
+ (mod_auth_ldap_config_t *)ap_get_module_config(r->per_dir_config,
+ &auth_ldap_module);
+
+ util_ldap_connection_t *ldc = NULL;
+ int m = r->method_number;
+
+ const apr_array_header_t *reqs_arr = ap_requires(r);
+ require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
+
+ register int x;
+ const char *t;
+ char *w;
+ int method_restricted = 0;
+
+ if (!sec->enabled) {
+ return DECLINED;
+ }
+
+ if (!sec->have_ldap_url) {
+ return DECLINED;
+ }
+
+ if (sec->host) {
+ ldc = util_ldap_connection_find(r, sec->host, sec->port,
+ sec->binddn, sec->bindpw, sec->deref,
+ sec->netscapessl, sec->starttls);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: no sec->host - weird...?", getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+
+ /*
+ * If there are no elements in the group attribute array, the default should be
+ * member and uniquemember; populate the array now.
+ */
+ if (sec->groupattr->nelts == 0) {
+ struct mod_auth_ldap_groupattr_entry_t *grp;
+ apr_lock_acquire(sec->lock);
+ grp = apr_array_push(sec->groupattr);
+ grp->name = "member";
+ grp = apr_array_push(sec->groupattr);
+ grp->name = "uniquemember";
+ apr_lock_release(sec->lock);
+ }
+
+ if (!reqs_arr) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: no requirements array", getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+
+ /* Loop through the requirements array until there's no elements
+ * left, or something causes a return from inside the loop */
+ for(x=0; x < reqs_arr->nelts; x++) {
+ if (! (reqs[x].method_mask & (1 << m))) {
+ continue;
+ }
+ method_restricted = 1;
+
+ t = reqs[x].requirement;
+ w = ap_getword(r->pool, &t, ' ');
+
+ if (strcmp(w, "valid-user") == 0) {
+ /*
+ * Valid user will always be true if we authenticated with ldap,
+ * but when using front page, valid user should only be true if
+ * he exists in the frontpage password file. This hack will get
+ * auth_ldap to look up the user in the the pw file to really be
+ * sure that he's valid. Naturally, it requires mod_auth to be
+ * compiled in, but if mod_auth wasn't in there, then the need
+ * for this hack wouldn't exist anyway.
+ */
+ if (sec->frontpage_hack) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "deferring authorisation to mod_auth (FP Hack)",
+ getpid());
+ return OK;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "successful authorisation because user "
+ "is valid-user", getpid());
+ return OK;
+ }
+ }
+ else if (strcmp(w, "user") == 0) {
+ if (req->dn == NULL || strlen(req->dn) == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require user: user's DN has not been defined; failing authorisation",
+ getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+ /*
+ * First do a whole-line compare, in case it's something like
+ * require user Babs Jensen
+ */
+ result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, t);
+ switch(result) {
+ case LDAP_COMPARE_TRUE: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require user: authorisation successful", getpid());
+ return OK;
+ }
+ default: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require user: "
+ "authorisation failed [%s][%s]", getpid(),
+ ldc->reason, ldap_err2string(result));
+ }
+ }
+ /*
+ * Now break apart the line and compare each word on it
+ */
+ while (t[0]) {
+ w = ap_getword_conf(r->pool, &t);
+ result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, w);
+ switch(result) {
+ case LDAP_COMPARE_TRUE: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require user: authorisation successful", getpid());
+ return OK;
+ }
+ default: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require user: authorisation failed [%s][%s]",
+ getpid(), ldc->reason, ldap_err2string(result));
+ }
+ }
+ }
+ }
+ else if (strcmp(w, "dn") == 0) {
+ if (req->dn == NULL || strlen(req->dn) == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require dn: user's DN has not been defined; failing authorisation",
+ getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+
+ result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, t, sec->compare_dn_on_server);
+ switch(result) {
+ case LDAP_COMPARE_TRUE: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require dn: authorisation successful", getpid());
+ return OK;
+ }
+ default: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: "
+ "require dn: LDAP error [%s][%s]",
+ getpid(), ldc->reason, ldap_err2string(result));
+ }
+ }
+ }
+ else if (strcmp(w, "group") == 0) {
+ struct mod_auth_ldap_groupattr_entry_t *ent = (struct mod_auth_ldap_groupattr_entry_t *) sec->groupattr->elts;
+ int i;
+
+ if (sec->group_attrib_is_dn) {
+ if (req->dn == NULL || strlen(req->dn) == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require group: user's DN has not been defined; failing authorisation",
+ getpid());
+ return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
+ }
+ }
+ else {
+ if (req->user == NULL || strlen(req->user) == 0) {
+ /* We weren't called in the authentication phase, so we didn't have a
+ * chance to set the user field. Do so now. */
+ req->user = r->user;
+ }
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require group: testing for group membership in `%s'",
+ getpid(), t);
+
+ for (i = 0; i < sec->groupattr->nelts; i++) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require group: testing for %s: %s (%s)", getpid(),
+ ent[i].name, sec->group_attrib_is_dn ? req->dn : req->user, t);
+
+ result = util_ldap_cache_compare(r, ldc, sec->url, t, ent[i].name,
+ sec->group_attrib_is_dn ? req->dn : req->user);
+ switch(result) {
+ case LDAP_COMPARE_TRUE: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require group: "
+ "authorisation successful (attribute %s) [%s][%s]",
+ getpid(), ent[i].name, ldc->reason, ldap_err2string(result));
+ return OK;
+ }
+ default: {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: require group: "
+ "authorisation failed [%s][%s]",
+ getpid(), ldc->reason, ldap_err2string(result));
+ }
+ }
+ }
+ }
+ }
+
+ if (!method_restricted) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: agreeing because non-restricted",
+ getpid());
+ return OK;
+ }
+
+ if (!sec->auth_authoritative) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: declining to authorise", getpid());
+ return DECLINED;
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
+ "[%d] auth_ldap authorise: authorisation denied", getpid());
+ ap_note_basic_auth_failure (r);
+
+ return HTTP_UNAUTHORIZED;
+}
+
+
+/* ---------------------------------------- */
+/* config directives */
+
+
+void *mod_auth_ldap_create_dir_config(apr_pool_t *p, char *d)
+{
+ mod_auth_ldap_config_t *sec =
+ (mod_auth_ldap_config_t *)apr_pcalloc(p, sizeof(mod_auth_ldap_config_t));
+
+ sec->pool = p;
+ apr_lock_create(&sec->lock, APR_MUTEX, APR_INTRAPROCESS, NULL, p);
+ sec->auth_authoritative = 1;
+ sec->enabled = 1;
+ sec->groupattr = apr_array_make(p, GROUPATTR_MAX_ELTS,
+ sizeof(struct mod_auth_ldap_groupattr_entry_t));
+
+ sec->have_ldap_url = 0;
+ sec->url = "";
+ sec->host = NULL;
+ sec->binddn = NULL;
+ sec->bindpw = NULL;
+ sec->deref = always;
+ sec->group_attrib_is_dn = 1;
+
+ sec->frontpage_hack = 0;
+ sec->netscapessl = 0;
+ sec->starttls = 0;
+
+ sec->user_is_dn = 0;
+ sec->compare_dn_on_server = 0;
+
+ return sec;
+}
+
+/*
+ * Use the ldap url parsing routines to break up the ldap url into
+ * host and port.
+ */
+static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
+ void *config,
+ const char *url)
+{
+ int result;
+ LDAPURLDesc *urld;
+
+ mod_auth_ldap_config_t *sec = config;
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: `%s'",
+ getpid(), url);
+
+ result = ldap_url_parse(url, &(urld));
+ if (result != LDAP_SUCCESS) {
+ switch (result) {
+ case LDAP_URL_ERR_NOTLDAP:
+ return "LDAP URL does not begin with ldap://";
+ case LDAP_URL_ERR_NODN:
+ return "LDAP URL does not have a DN";
+ case LDAP_URL_ERR_BADSCOPE:
+ return "LDAP URL has an invalid scope";
+ case LDAP_URL_ERR_MEM:
+ return "Out of memory parsing LDAP URL";
+ default:
+ return "Could not parse LDAP URL";
+ }
+ }
+ sec->url = apr_pstrdup(cmd->pool, url);
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: Host: %s", getpid(), urld->lud_host);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: Port: %d", getpid(), urld->lud_port);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: DN: %s", getpid(), urld->lud_dn);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: attrib: %s", getpid(), urld->lud_attrs? urld->lud_attrs[0] : "(null)");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: scope: %s", getpid(),
+ (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
+ urld->lud_scope == LDAP_SCOPE_BASE? "base" :
+ urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap url parse: filter: %s", getpid(), urld->lud_filter);
+
+ /* Set all the values, or at least some sane defaults */
+ if (sec->host) {
+ char *p = apr_palloc(cmd->pool, strlen(sec->host) + strlen(urld->lud_host) + 2);
+ strcpy(p, urld->lud_host);
+ strcat(p, " ");
+ strcat(p, sec->host);
+ sec->host = p;
+ }
+ else {
+ sec->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
+ }
+ sec->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
+ if (urld->lud_attrs && urld->lud_attrs[0]) {
+ int i = 1;
+ while (urld->lud_attrs[i]) {
+ i++;
+ }
+ sec->attributes = apr_pcalloc(cmd->pool, sizeof(char *) * (i+1));
+ i = 0;
+ while (urld->lud_attrs[i]) {
+ sec->attributes[i] = apr_pstrdup(cmd->pool, urld->lud_attrs[i]);
+ i++;
+ }
+ sec->attribute = sec->attributes[0];
+ }
+ else {
+ sec->attribute = "uid";
+ }
+
+ sec->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
+ LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
+
+ if (urld->lud_filter) {
+ if (urld->lud_filter[0] == '(') {
+ /*
+ * Get rid of the surrounding parens; later on when generating the
+ * filter, they'll be put back.
+ */
+ sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1);
+ sec->filter[strlen(sec->filter)-1] = '\0';
+ }
+ else {
+ sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
+ }
+ }
+ else {
+ sec->filter = "objectclass=*";
+ }
+ if (strncmp(url, "ldaps", 5) == 0) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap parse url: requesting secure LDAP", getpid());
+#ifdef APU_HAS_LDAP_STARTTLS
+ sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
+ sec->starttls = 1;
+#else
+#ifdef APU_HAS_LDAP_NETSCAPE_SSL
+ sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
+ sec->netscapessl = 1;
+#else
+ return "Secure LDAP (ldaps://) not supported. Rebuild APR-Util";
+#endif
+#endif
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+ cmd->server, "[%d] auth_ldap parse url: not requesting secure LDAP", getpid());
+ sec->netscapessl = 0;
+ sec->starttls = 0;
+ sec->port = urld->lud_port? urld->lud_port : LDAP_PORT;
+ }
+
+ sec->have_ldap_url = 1;
+ ldap_free_urldesc(urld);
+ return NULL;
+}
+
+static const char *mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const char *arg)
+{
+ mod_auth_ldap_config_t *sec = config;
+
+ if (strcmp(arg, "never") == 0 || strcasecmp(arg, "off") == 0) {
+ sec->deref = never;
+ }
+ else if (strcmp(arg, "searching") == 0) {
+ sec->deref = searching;
+ }
+ else if (strcmp(arg, "finding") == 0) {
+ sec->deref = finding;
+ }
+ else if (strcmp(arg, "always") == 0 || strcasecmp(arg, "on") == 0) {
+ sec->deref = always;
+ }
+ else {
+ return "Unrecognized value for AuthLDAPAliasDereference directive";
+ }
+ return NULL;
+}
+
+static const char *mod_auth_ldap_add_group_attribute(cmd_parms *cmd, void *config, const char *arg)
+{
+ struct mod_auth_ldap_groupattr_entry_t *new;
+
+ mod_auth_ldap_config_t *sec = config;
+
+ if (sec->groupattr->nelts > GROUPATTR_MAX_ELTS)
+ return "Too many AuthLDAPGroupAttribute directives";
+
+ new = apr_array_push(sec->groupattr);
+ new->name = apr_pstrdup(cmd->pool, arg);
+
+ return NULL;
+}
+
+command_rec mod_auth_ldap_cmds[] = {
+ AP_INIT_TAKE1("AuthLDAPURL", mod_auth_ldap_parse_url, NULL, OR_AUTHCFG,
+ "URL to define LDAP connection. This should be an RFC 2255 complaint\n"
+ "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
+ "
\n"
+ "
Host is the name of the LDAP server. Use a space separated list of hosts \n"
+ "to specify redundant servers.\n"
+ "
Port is optional, and specifies the port to connect to.\n"
+ "
basedn specifies the base DN to start searches from\n"
+ "
Attrib specifies what attribute to search for in the directory. If not "
+ "provided, it defaults to uid.\n"
+ "
Scope is the scope of the search, and can be either sub or "
+ "one. If not provided, the default is sub.\n"
+ "
Filter is a filter to use in the search. If not provided, "
+ "defaults to (objectClass=*).\n"
+ "
\n"
+ "Searches are performed using the attribute and the filter combined. "
+ "For example, assume that the\n"
+ "LDAP URL is ldap://ldap.airius.com/ou=People, o=Airius?uid?sub?(posixid=*). "
+ "Searches will\n"
+ "be done using the filter (&((posixid=*))(uid=username)), "
+ "where username\n"
+ "is the user name passed by the HTTP client. The search will be a subtree "
+ "search on the branch ou=People, o=Airius."),
+
+ AP_INIT_TAKE1("AuthLDAPBindDN", ap_set_string_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, binddn), OR_AUTHCFG,
+ "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
+
+ AP_INIT_TAKE1("AuthLDAPBindPassword", ap_set_string_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, bindpw), OR_AUTHCFG,
+ "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
+
+ AP_INIT_FLAG("AuthLDAPRemoteUserIsDN", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, user_is_dn), OR_AUTHCFG,
+ "Set to 'on' to set the REMOTE_USER environment variable to be the full "
+ "DN of the remote user. By default, this is set to off, meaning that "
+ "the REMOTE_USER variable will contain whatever value the remote user sent."),
+
+ AP_INIT_FLAG("AuthLDAPAuthoritative", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, auth_authoritative), OR_AUTHCFG,
+ "Set to 'off' to allow access control to be passed along to lower modules if "
+ "the UserID and/or group is not known to this module"),
+
+ AP_INIT_FLAG("AuthLDAPCompareDNOnServer", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, compare_dn_on_server), OR_AUTHCFG,
+ "Set to 'on' to force auth_ldap to do DN compares (for the \"require dn\" "
+ "directive) using the server, and set it 'off' to do the compares locally "
+ "(at the expense of possible false matches). See the documentation for "
+ "a complete description of this option."),
+
+ AP_INIT_ITERATE("AuthLDAPGroupAttribute", mod_auth_ldap_add_group_attribute, NULL, OR_AUTHCFG,
+ "A list of attributes used to define group membership - defaults to "
+ "member and uniquemember"),
+
+ AP_INIT_FLAG("AuthLDAPGroupAttributeIsDN", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, group_attrib_is_dn), OR_AUTHCFG,
+ "If set to 'on', auth_ldap uses the DN that is retrieved from the server for"
+ "subsequent group comparisons. If set to 'off', auth_ldap uses the string"
+ "provided by the client directly. Defaults to 'on'."),
+
+ AP_INIT_TAKE1("AuthLDAPDereferenceAliases", mod_auth_ldap_set_deref, NULL, OR_AUTHCFG,
+ "Determines how aliases are handled during a search. Can bo one of the"
+ "values \"never\", \"searching\", \"finding\", or \"always\". "
+ "Defaults to always."),
+
+ AP_INIT_FLAG("AuthLDAPEnabled", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, enabled), OR_AUTHCFG,
+ "Set to off to disable auth_ldap, even if it's been enabled in a higher tree"),
+
+ AP_INIT_FLAG("AuthLDAPFrontPageHack", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, frontpage_hack), OR_AUTHCFG,
+ "Set to 'on' to support Microsoft FrontPage"),
+
+#ifdef APU_HAS_LDAP_STARTTLS
+ AP_INIT_FLAG("AuthLDAPStartTLS", ap_set_flag_slot,
+ (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, starttls), OR_AUTHCFG,
+ "Set to 'on' to start TLS after connecting to the LDAP server."),
+#endif /* APU_HAS_LDAP_STARTTLS */
+
+ {NULL}
+};
+
+static void mod_auth_ldap_register_hooks(apr_pool_t *p)
+{
+ ap_hook_check_user_id(mod_auth_ldap_check_user_id, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_auth_checker(mod_auth_ldap_auth_checker, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module auth_ldap_module = {
+ STANDARD20_MODULE_STUFF,
+ mod_auth_ldap_create_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ mod_auth_ldap_cmds, /* command table */
+ mod_auth_ldap_register_hooks, /* set up request processing hooks */
+};
diff --git a/modules/experimental/mod_cache.dsp b/modules/experimental/mod_cache.dsp
new file mode 100644
index 00000000000..f62455d62dd
--- /dev/null
+++ b/modules/experimental/mod_cache.dsp
@@ -0,0 +1,123 @@
+# Microsoft Developer Studio Project File - Name="mod_cache" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_cache - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_cache.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_cache.mak" CFG="mod_cache - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_cache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_cache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_cache - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_CACHE_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CACHE_DECLARE_EXPORT" /D "MOD_CACHE_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/mod_cache.so"
+
+!ELSEIF "$(CFG)" == "mod_cache - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_CACHE_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CACHE_DECLARE_EXPORT" /D "MOD_CACHE_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/mod_cache.so" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_cache - Win32 Release"
+# Name "mod_cache - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\cache_storage.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cache_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_mem_cache.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\mod_cache.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/modules/experimental/mod_case_filter_in.c b/modules/experimental/mod_case_filter_in.c
new file mode 100644
index 00000000000..e4ab97feab4
--- /dev/null
+++ b/modules/experimental/mod_case_filter_in.c
@@ -0,0 +1,131 @@
+// Ben messing around some more...
+
+#include "httpd.h"
+#include "http_config.h"
+#include "apr_general.h"
+#include "util_filter.h"
+#include "apr_buckets.h"
+#include "http_request.h"
+
+#include
+
+static const char s_szCaseFilterName[]="CaseFilter";
+module case_filter_in_module;
+
+typedef struct
+{
+ int bEnabled;
+} CaseFilterInConfig;
+
+typedef struct
+{
+ apr_bucket_brigade *pbbTmp;
+} CaseFilterInContext;
+
+static void *CaseFilterInCreateServerConfig(apr_pool_t *p,server_rec *s)
+{
+ CaseFilterInConfig *pConfig=apr_pcalloc(p,sizeof *pConfig);
+
+ pConfig->bEnabled=0;
+
+ return pConfig;
+}
+
+static void CaseFilterInInsertFilter(request_rec *r)
+{
+ CaseFilterInConfig *pConfig=ap_get_module_config(r->server->module_config,
+ &case_filter_in_module);
+ CaseFilterInContext *pCtx;
+
+ if(!pConfig->bEnabled)
+ return;
+
+ pCtx=apr_palloc(r->pool,sizeof *pCtx);
+ pCtx->pbbTmp=apr_brigade_create(r->pool);
+ ap_add_input_filter(s_szCaseFilterName,pCtx,r,NULL);
+}
+
+static apr_status_t CaseFilterInFilter(ap_filter_t *f,
+ apr_bucket_brigade *pbbOut,
+ ap_input_mode_t eMode,apr_size_t nBytes)
+{
+ CaseFilterInContext *pCtx=f->ctx;
+ apr_status_t ret;
+
+ ap_assert(APR_BRIGADE_EMPTY(pCtx->pbbTmp));
+
+ ret=ap_get_brigade(f->next,pCtx->pbbTmp,eMode,nBytes);
+ if(eMode == AP_MODE_PEEK || ret != APR_SUCCESS)
+ return ret;
+
+ while(!APR_BRIGADE_EMPTY(pCtx->pbbTmp)) {
+ apr_bucket *pbktIn=APR_BRIGADE_FIRST(pCtx->pbbTmp);
+ apr_bucket *pbktOut;
+ const char *data;
+ apr_size_t len;
+ char *buf;
+ int n;
+
+ // It is tempting to do this...
+ //APR_BUCKET_REMOVE(pB);
+ //APR_BRIGADE_INSERT_TAIL(pbbOut,pB);
+ // and change the case of the bucket data, but that would be wrong
+ // for a file or socket buffer, for example...
+
+ if(APR_BUCKET_IS_EOS(pbktIn)) {
+ APR_BUCKET_REMOVE(pbktIn);
+ APR_BRIGADE_INSERT_TAIL(pbbOut,pbktIn);
+ break;
+ }
+
+ ret=apr_bucket_read(pbktIn,&data,&len,eMode);
+ if(ret != APR_SUCCESS)
+ return ret;
+
+ buf=malloc(len);
+ for(n=0 ; n < len ; ++n)
+ buf[n]=toupper(data[n]);
+
+ pbktOut=apr_bucket_heap_create(buf,len,0,NULL);
+ APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut);
+ apr_bucket_delete(pbktIn);
+ }
+
+ return APR_SUCCESS;
+}
+
+
+static const char *CaseFilterEnable(cmd_parms *cmd, void *dummy, int arg)
+ {
+ CaseFilterInConfig *pConfig
+ =ap_get_module_config(cmd->server->module_config,&case_filter_in_module);
+ pConfig->bEnabled=arg;
+
+ return NULL;
+ }
+
+static const command_rec CaseFilterInCmds[] =
+ {
+ AP_INIT_FLAG("CaseFilterIn", CaseFilterEnable, NULL, RSRC_CONF,
+ "Run an input case filter on this host"),
+ { NULL }
+ };
+
+
+static void CaseFilterInRegisterHooks(apr_pool_t *p)
+ {
+ ap_hook_insert_filter(CaseFilterInInsertFilter,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_register_input_filter(s_szCaseFilterName,CaseFilterInFilter,
+ AP_FTYPE_CONTENT);
+ }
+
+module case_filter_in_module =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL,
+ NULL,
+ CaseFilterInCreateServerConfig,
+ NULL,
+ CaseFilterInCmds,
+ CaseFilterInRegisterHooks
+};
diff --git a/modules/experimental/mod_mem_cache.c b/modules/experimental/mod_mem_cache.c
new file mode 100644
index 00000000000..2d2781a1a22
--- /dev/null
+++ b/modules/experimental/mod_mem_cache.c
@@ -0,0 +1,509 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_cache.h"
+#define MAX_CACHE 5000
+module AP_MODULE_DECLARE_DATA mem_cache_module;
+
+/*
+ * XXX
+ * This cache uses apr_hash functions which leak storage when something is removed
+ * from the cache. This can be fixed in the apr_hash functions by making them use
+ * malloc/free rather than pools to manage their storage requirements.
+ */
+
+/*
+ * XXX Introduce a type field that identifies whether the cache obj
+ * references malloc'ed or mmap storage or a file descriptor
+ */
+typedef enum {
+ CACHE_TYPE_FILE = 1,
+ CACHE_TYPE_MALLOC,
+ CACHE_TYPE_MMAP
+} cache_type_e;
+
+typedef struct {
+ cache_type_e type;
+ char *key;
+ void *m;
+ apr_size_t m_len;
+ cache_info info;
+ int complete;
+} cache_object_t;
+
+typedef struct {
+ apr_lock_t *lock;
+ apr_hash_t *cacheht;
+ int space;
+ apr_time_t maxexpire;
+ apr_time_t defaultexpire;
+} mem_cache_conf;
+static mem_cache_conf *sconf;
+
+#define DEFAULT_CACHE_SPACE 100*1024
+#define CACHEFILE_LEN 20
+
+/* Forward declarations */
+static int remove_entity(cache_handle *h);
+static int write_headers(cache_handle *h, request_rec *r, cache_info *i);
+static int write_body(cache_handle *h, apr_bucket_brigade *b);
+static int read_headers(cache_handle *h, request_rec *r, cache_info **info);
+static int read_body(cache_handle *h, apr_bucket_brigade *bb);
+
+static void cleanup_cache_object(cache_object_t *obj)
+{
+ /* The cache object has been removed from the cache. Now clean
+ * it up, freeing any storage, closing file descriptors, etc.
+ */
+ /* XXX -
+ * The action of freeing a cache entry is asynchronous with the rest of
+ * the operation of the cache. Frees can be driven by garbage collection,
+ * the result of some command or an HTTP request. It is okay to remove
+ * an entry from the cache at anytime but we need a mechanism to keep
+ * us from cleaning up the cache entry out from under other threads
+ * that may still be referencing it.
+ *
+ * Bill thinks that we need a special purpose reference counted
+ * bucket (or three). When an entry is removed from the cache, the
+ * bucket for that entry is marked for cleanup. A bucket marked for
+ * cleanup is freed by the last routine referencing the bucket,
+ * either during brigade destroy or this routine.
+ */
+
+ /*
+ * Ref count decrementing and checking needs to be atomic
+
+ obj->ref_count--;
+ if (obj->ref_count) {
+ defer_cleanup (let the brigade cleanup free the bucket)
+ }
+ else {
+ free the bucket
+ }
+ */
+
+ if (obj->info.content_type)
+ free(obj->info.content_type);
+ if (obj->key)
+ free(obj->key);
+ if (obj->m)
+ free(obj->m);
+
+ free(obj);
+}
+
+static apr_status_t cleanup_cache_mem(void *sconfv)
+{
+ cache_object_t *obj;
+ apr_hash_index_t *hi;
+ mem_cache_conf *co = (mem_cache_conf*) sconfv;
+
+ if (!co) {
+ return APR_SUCCESS;
+ }
+
+ /* Iterate over the frag hash table and clean up each entry */
+ /* XXX need to lock the hash */
+ for (hi = apr_hash_first(NULL, co->cacheht); hi; hi=apr_hash_next(hi)) {
+ apr_hash_this(hi, NULL, NULL, (void **)&obj);
+ if (obj)
+ cleanup_cache_object(obj);
+ }
+ return APR_SUCCESS;
+}
+static void *create_cache_config(apr_pool_t *p, server_rec *s)
+{
+ sconf = apr_pcalloc(p, sizeof(mem_cache_conf));
+ sconf->space = DEFAULT_CACHE_SPACE;
+#if 0
+ sconf->maxexpire = DEFAULT_CACHE_MAXEXPIRE;
+ sconf->defaultexpire = DEFAULT_CACHE_EXPIRE;
+#endif
+
+ apr_lock_create(&sconf->lock, APR_MUTEX, APR_INTRAPROCESS, "foo", p);
+ sconf->cacheht = apr_hash_make(p);
+ apr_pool_cleanup_register(p, NULL, cleanup_cache_mem, apr_pool_cleanup_null);
+
+ return sconf;
+}
+
+static int create_entity(cache_handle **hp, const char *type, char *key, apr_size_t len)
+{
+ apr_status_t rv;
+ cache_object_t *obj;
+ cache_handle *h;
+
+ /* Create the cache handle and begin populating it.
+ */
+ if (strcasecmp(type, "mem")) {
+ return DECLINED;
+ }
+
+ /* Check len to see if it is withing acceptable bounds
+ * XXX max cache check should be configurable variable.
+ */
+ if (len < 0 || len > MAX_CACHE) {
+ return DECLINED;
+ }
+ /* Check total cache size and number of entries. Are they within the
+ * configured limits? If not, kick off garbage collection thread.
+ */
+
+ /* Allocate the cache_handle and set up call back functions specific to
+ * this cache handler.
+ */
+ h = malloc(sizeof(cache_handle));
+ *hp = h;
+ if (!h) {
+ /* handle the error */
+ return DECLINED;
+ }
+ h->read_body = &read_body;
+ h->read_headers = &read_headers;
+ h->write_body = &write_body;
+ h->write_headers = &write_headers;
+
+ /* Allocate and initialize the cache object. The cache object is
+ * unique to this implementation.
+ */
+ obj = malloc(sizeof(*obj));
+ if (!obj) {
+ /* Handle ther error */
+ free(h);
+ return DECLINED;
+ }
+
+ obj->key = malloc(strlen(key));
+ if (!obj->key) {
+ /* XXX Uuugh, there has got to be a better way to manage memory.
+ */
+ free(h);
+ free(obj);
+ return DECLINED;
+ }
+ obj->m_len = len; /* One of these len fields can go */
+ obj->info.len = len;
+ strcpy(obj->key, key);
+ h->cache_obj = (void *) obj;
+
+ /* Mark the cache object as incomplete and put it into the cache */
+ obj->complete = 0;
+
+ /* XXX Need a way to insert into the cache w/o sch coarse grained locking */
+ apr_lock_acquire(sconf->lock);
+ apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), obj);
+ apr_lock_release(sconf->lock);
+}
+
+static int open_entity(cache_handle **hp, const char *type, char *key)
+{
+ cache_object_t *obj;
+ cache_handle *h;
+
+ /* Look up entity keyed to 'url' */
+ if (strcasecmp(type, "mem")) {
+ return DECLINED;
+ }
+ apr_lock_acquire(sconf->lock);
+ obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING);
+ apr_lock_release(sconf->lock);
+
+ if (!obj || !(obj->complete)) {
+ return DECLINED;
+ }
+
+ /* Allocate the cache_handle and initialize it */
+ h = malloc(sizeof(cache_handle));
+ *hp = h;
+ if (!h) {
+ /* handle the error */
+ return DECLINED;
+ }
+ h->read_body = &read_body;
+ h->read_headers = &read_headers;
+ h->write_body = &write_body;
+ h->write_headers = &write_headers;
+ h->cache_obj = obj;
+ if (!obj || !(obj->complete)) {
+ return DECLINED;
+ }
+ return OK;
+}
+
+static int remove_entity(cache_handle *h)
+{
+ cache_object_t *obj = (cache_object_t *) h->cache_obj;
+
+ apr_lock_acquire(sconf->lock);
+ apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), NULL);
+ apr_lock_release(sconf->lock);
+
+ cleanup_cache_object(obj);
+
+ /* Reinit the cache_handle fields? */
+ h->cache_obj = NULL;
+
+ /* The caller should free the cache_handle ? */
+ free(h);
+}
+
+/* Define request processing hook handlers */
+static int remove_url(const char *type, char *key)
+{
+ cache_object_t *obj;
+
+ if (strcasecmp(type, "mem")) {
+ return DECLINED;
+ }
+
+ /* WIBNIF
+ * apr_hash_set(..,..,..,NULL) returned pointer to the object just removed.
+ * That way, we could free the object w/o doing another call to an
+ * apr_hash function.
+ */
+
+ /* First, find the object in the cache */
+ apr_lock_acquire(sconf->lock);
+ obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING);
+ apr_lock_release(sconf->lock);
+
+ if (!obj) {
+ return DECLINED;
+ }
+
+ /* Found it. Now take it out of the cache and free it. */
+ apr_lock_acquire(sconf->lock);
+ apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), NULL);
+ apr_lock_release(sconf->lock);
+
+ cleanup_cache_object(obj);
+
+ return OK;
+}
+
+static int read_headers(cache_handle *h, request_rec *r, cache_info **info)
+{
+ cache_object_t *obj = (cache_object_t*) h->cache_obj;
+
+ *info = &(obj->info);
+
+ return OK;
+}
+
+static int read_body(cache_handle *h, apr_bucket_brigade *bb)
+{
+ apr_bucket *b;
+ cache_object_t *obj = h->cache_obj;
+
+ b = apr_bucket_immortal_create(obj->m, obj->m_len);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ b = apr_bucket_eos_create();
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+
+ return OK;
+}
+
+static int write_headers(cache_handle *h, request_rec *r, cache_info *info)
+{
+ apr_size_t len;
+ cache_object_t *obj = (cache_object_t*) h->cache_obj;
+ if (info->date) {
+ obj->info.date = info->date;
+ }
+ if (info->lastmod) {
+ obj->info.lastmod = info->lastmod;
+ }
+ if (info->expire) {
+ obj->info.expire = info->expire;
+ }
+ if (info->content_type) {
+ obj->info.content_type = (char*) malloc(strlen(info->content_type));
+ if (obj->info.content_type)
+ strcpy(obj->info.content_type, info->content_type);
+ }
+
+ return OK;
+}
+
+static int write_body(cache_handle *h, apr_bucket_brigade *b)
+{
+ apr_status_t rv;
+ apr_size_t idx = 0;
+ cache_object_t *obj = (cache_object_t *) h->cache_obj;
+ apr_read_type_e eblock = APR_BLOCK_READ;
+ apr_bucket *e;
+
+ /* XXX mmap, malloc or file?
+ * Enable this decision to be configured....
+ */
+ char *m = malloc(obj->m_len);
+ obj->m = m;
+ if (!m) {
+ /* Cleanup cache entry and return */
+ }
+ obj->type = CACHE_TYPE_MALLOC;
+
+ /* Iterate accross the brigade and populate the cache storage */
+ /* XXX doesn't handle multiple brigades */
+ APR_BRIGADE_FOREACH(e, b) {
+ const char *s;
+ apr_size_t len;
+
+ rv = apr_bucket_read(e, &s, &len, eblock);
+ if (rv != APR_SUCCESS) {
+ /* Big problem! Cleanup cache entry and return */
+ }
+ /* XXX Check for overflow */
+ if (len ) {
+ memcpy(m, s, len);
+ m+=len;
+ }
+ }
+
+ /* XXX - Check for EOS before setting obj->complete
+ * Open for business. This entry can be served from the cache
+ */
+ obj->complete = 1;
+ return OK;
+}
+
+static const char
+*set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
+{
+ int val;
+
+ if (sscanf(arg, "%d", &val) != 1)
+ return "CacheSize value must be an integer (kBytes)";
+ sconf->space = val;
+ return NULL;
+}
+#if 0
+static const char
+*set_cache_factor(cmd_parms *parms, void *dummy, char *arg)
+{
+ double val;
+
+ if (sscanf(arg, "%lg", &val) != 1)
+ return "CacheLastModifiedFactor value must be a float";
+ sconf->lmfactor = val;
+
+ return NULL;
+}
+#endif
+#if 0
+static const char
+*set_cache_maxex(cmd_parms *parms, void *dummy, char *arg)
+{
+ mem_cache_conf *pc = ap_get_module_config(parms->server->module_config, &mem_cache_module);
+ double val;
+
+ if (sscanf(arg, "%lg", &val) != 1)
+ return "CacheMaxExpire value must be a float";
+ sconf->maxexpire = (apr_time_t) (val * MSEC_ONE_HR);
+ return NULL;
+}
+#endif
+#if 0
+static const char
+*set_cache_defex(cmd_parms *parms, void *dummy, char *arg)
+{
+ mem_cache_conf *pc = ap_get_module_config(parms->server->module_config, &mem_cache_module);
+ double val;
+
+ if (sscanf(arg, "%lg", &val) != 1)
+ return "CacheDefaultExpire value must be a float";
+ pc->defaultexpire = (apr_time_t) (val * MSEC_ONE_HR);
+ return NULL;
+}
+#endif
+static const command_rec cache_cmds[] =
+{
+ /* XXX
+ * What config directives does this module need?
+ * Should this module manage expire policy for its entries?
+ * Certainly cache limits like max number of entries,
+ * max entry size, and max size of the cache should
+ * be managed by this module.
+ */
+ AP_INIT_TAKE1("CacheSizeMem", set_cache_size, NULL, RSRC_CONF,
+ "The maximum disk space used by the cache in Kb"),
+ {NULL}
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ /* cache initializer */
+/* cache_hook_cache_init(cache_init, NULL, NULL, AP_HOOK_FIRST); */
+ cache_hook_create_entity(create_entity, NULL, NULL, APR_HOOK_MIDDLE);
+ cache_hook_open_entity(open_entity, NULL, NULL, APR_HOOK_MIDDLE);
+ cache_hook_remove_url(remove_url, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA mem_cache_module =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ create_cache_config, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ cache_cmds, /* command apr_table_t */
+ register_hooks
+};
+
diff --git a/modules/experimental/util_ldap.c b/modules/experimental/util_ldap.c
new file mode 100644
index 00000000000..4e9ca0e5015
--- /dev/null
+++ b/modules/experimental/util_ldap.c
@@ -0,0 +1,1105 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+/*
+ * util_ldap.c: LDAP things
+ *
+ * Original code from auth_ldap module for Apache v1.3:
+ * Copyright 1998, 1999 Enbridge Pipelines Inc.
+ * Copyright 1999-2001 Dave Carrigan
+ */
+
+#include
+
+#ifdef APU_HAS_LDAP
+
+#include
+#include
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "util_ldap.h"
+#include "util_ldap_cache.h"
+
+#if APR_HAVE_UNISTD_H
+#include
+#endif
+
+module AP_MODULE_DECLARE_DATA ldap_module;
+
+int util_ldap_handler(request_rec *r);
+void *util_ldap_create_config(apr_pool_t *p, server_rec *s);
+
+
+/*
+ * Some definitions to help between various versions of apache.
+ */
+
+#ifndef DOCTYPE_HTML_2_0
+#define DOCTYPE_HTML_2_0 "\n"
+#endif
+
+#ifndef DOCTYPE_HTML_3_2
+#define DOCTYPE_HTML_3_2 "\n"
+#endif
+
+#ifndef DOCTYPE_HTML_4_0S
+#define DOCTYPE_HTML_4_0S "\n"
+#endif
+
+#ifndef DOCTYPE_HTML_4_0T
+#define DOCTYPE_HTML_4_0T "\n"
+#endif
+
+#ifndef DOCTYPE_HTML_4_0F
+#define DOCTYPE_HTML_4_0F "\n"
+#endif
+
+/*
+ * Status Handler
+ * --------------
+ *
+ * This handler generates a status page about the current performance of
+ * the LDAP cache. It is enabled as follows:
+ *
+ *
+ * SetHandler ldap-status
+ *
+ *
+ */
+int util_ldap_handler(request_rec *r)
+{
+
+ r->allowed |= (1 << M_GET);
+ if (r->method_number != M_GET)
+ return DECLINED;
+
+ if (strcmp(r->handler, "ldap-status")) {
+ return DECLINED;
+ }
+
+ r->content_type = "text/html";
+ if (r->header_only)
+ return OK;
+
+ ap_rputs(DOCTYPE_HTML_3_2
+ "LDAP Cache Information\n", r);
+ ap_rputs("
";
+ }
+
+ buf = util_ald_cache_display_stats(pool, util_ldap_cache, "LDAP URL Cache");
+
+ for (i=0; i < util_ldap_cache->size; ++i) {
+ util_cache_node_t *p;
+ for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
+ util_url_node_t *n;
+
+ n = (util_url_node_t *)p->payload;
+
+ t1 = apr_psprintf(pool, "%s (Searches)", n->url);
+ t2 = apr_psprintf(pool, "%s (Compares)", n->url);
+ t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
+
+ buf = apr_psprintf(pool, "%s\n\n"
+ "%s\n\n"
+ "%s\n\n"
+ "%s\n\n",
+ buf,
+ util_ald_cache_display_stats(pool, n->search_cache, t1),
+ util_ald_cache_display_stats(pool, n->compare_cache, t2),
+ util_ald_cache_display_stats(pool, n->dn_compare_cache, t3)
+ );
+ }
+ }
+ return buf;
+}
+
+#endif /* APU_HAS_LDAP */
diff --git a/modules/generators/mod_cgi.h b/modules/generators/mod_cgi.h
new file mode 100644
index 00000000000..4eadfaa58ad
--- /dev/null
+++ b/modules/generators/mod_cgi.h
@@ -0,0 +1,79 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef _MOD_CGI_H
+#define _MOD_CGI_H 1
+
+
+/**
+ * Registerable optional function to override CGI behavior;
+ * Reprocess the command and arguments to execute the given CGI script.
+ * @param cmd Pointer to the command to execute (may be overridden)
+ * @param argv Pointer to the arguments to pass (may be overridden)
+ * @param r The current request
+ * @param p The pool to allocate correct cmd/argv elements within.
+ * @deffunc apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv, request_rec *r, apr_pool_t *p)
+ * @tip This callback may be registered by the os-specific module
+ * to correct the command and arguments for apr_proc_create invocation
+ * on a given os. mod_cgi will call the function if registered.
+ */
+APR_DECLARE_OPTIONAL_FN(apr_status_t, ap_cgi_build_command,
+ (const char **cmd, const char ***argv,
+ request_rec *r, apr_pool_t *p));
+
+#endif /* _MOD_CGI_H */
diff --git a/modules/mappers/mod_vhost_alias.dsp b/modules/mappers/mod_vhost_alias.dsp
new file mode 100644
index 00000000000..7a892bf83d7
--- /dev/null
+++ b/modules/mappers/mod_vhost_alias.dsp
@@ -0,0 +1,128 @@
+# Microsoft Developer Studio Project File - Name="mod_vhost_alias" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_vhost_alias - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_vhost_alias.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_vhost_alias.mak" CFG="mod_vhost_alias - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_vhost_alias - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_vhost_alias - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_vhost_alias - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_vhost_alias" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_vhost_alias.so" /base:@..\..\os\win32\BaseAddr.ref,mod_vhost_alias
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_vhost_alias.so" /base:@..\..\os\win32\BaseAddr.ref,mod_vhost_alias
+
+!ELSEIF "$(CFG)" == "mod_vhost_alias - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_vhost_alias" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_vhost_alias.so" /base:@..\..\os\win32\BaseAddr.ref,mod_vhost_alias
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_vhost_alias.so" /base:@..\..\os\win32\BaseAddr.ref,mod_vhost_alias
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_vhost_alias - Win32 Release"
+# Name "mod_vhost_alias - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_vhost_alias.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_vhost_alias.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_vhost_alias - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_vhost_alias.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_vhost_alias "vhost_alias_module for Apache" ../../include/ap_release.h > .\mod_vhost_alias.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_vhost_alias - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_vhost_alias.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_vhost_alias "vhost_alias_module for Apache" ../../include/ap_release.h > .\mod_vhost_alias.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/modules/metadata/mod_mime_magic.dsp b/modules/metadata/mod_mime_magic.dsp
new file mode 100644
index 00000000000..f831ae4ec87
--- /dev/null
+++ b/modules/metadata/mod_mime_magic.dsp
@@ -0,0 +1,128 @@
+# Microsoft Developer Studio Project File - Name="mod_mime_magic" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_mime_magic - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_mime_magic.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_mime_magic.mak" CFG="mod_mime_magic - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_mime_magic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_mime_magic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_mime_magic - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_mime_magic" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_mime_magic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_mime_magic
+# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_mime_magic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_mime_magic
+
+!ELSEIF "$(CFG)" == "mod_mime_magic - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_mime_magic" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_mime_magic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_mime_magic
+# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_mime_magic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_mime_magic
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_mime_magic - Win32 Release"
+# Name "mod_mime_magic - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_mime_magic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_mime_magic.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_mime_magic - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_mime_magic.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_mime_magic "mime_magic_module for Apache" ../../include/ap_release.h > .\mod_mime_magic.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_mime_magic - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_mime_magic.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_mime_magic "mime_magic_module for Apache" ../../include/ap_release.h > .\mod_mime_magic.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/modules/metadata/mod_unique_id.dsp b/modules/metadata/mod_unique_id.dsp
new file mode 100644
index 00000000000..3045d2fc230
--- /dev/null
+++ b/modules/metadata/mod_unique_id.dsp
@@ -0,0 +1,128 @@
+# Microsoft Developer Studio Project File - Name="mod_unique_id" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_unique_id - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_unique_id.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_unique_id.mak" CFG="mod_unique_id - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_unique_id - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_unique_id - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_unique_id - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_unique_id" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_unique_id.so" /base:@..\..\os\win32\BaseAddr.ref,mod_unique_id
+# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:"Release/mod_unique_id.so" /base:@..\..\os\win32\BaseAddr.ref,mod_unique_id
+
+!ELSEIF "$(CFG)" == "mod_unique_id - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_unique_id" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_unique_id.so" /base:@..\..\os\win32\BaseAddr.ref,mod_unique_id
+# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"Debug/mod_unique_id.so" /base:@..\..\os\win32\BaseAddr.ref,mod_unique_id
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_unique_id - Win32 Release"
+# Name "mod_unique_id - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_unique_id.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_unique_id.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_unique_id - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_unique_id.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_unique_id "unique_id_module for Apache" ../../include/ap_release.h > .\mod_unique_id.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_unique_id - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_unique_id.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_unique_id "unique_id_module for Apache" ../../include/ap_release.h > .\mod_unique_id.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/modules/proxy/CHANGES b/modules/proxy/CHANGES
new file mode 100644
index 00000000000..d03f68c932b
--- /dev/null
+++ b/modules/proxy/CHANGES
@@ -0,0 +1,134 @@
+
+mod_proxy changes for httpd 2.0.18-dev
+
+ *) Reverse previous patch since the core reverted.
+ [Chuck Murcko ]
+
+ *) Remove indirection on number of bytes to read for input filters.
+ [Chuck Murcko ]
+
+ *) Fixed a problem with directory listing corruption in the
+ PROXY_DIR filter.
+ [Graham Leggett ]
+
+ *) mod_proxy and the proxy submodules now build properly as DSOs.
+ [Graham Leggett ]
+
+ *) Stopped the HTTP proxy from trying to read entity bodies when there
+ wasn't one (response was 1xx, 204, 205 or 304).
+ [Graham Leggett ]
+
+ *) Made sure dates were canonicalised correctly when passed to the client
+ browser through the HTTP proxy.
+ [Graham Leggett ]
+
+ *) Split each individual proxy protocol into separate modules.
+ [Graham Leggett ]
+
+ *) Added Max-Forwards support for all request types so as to prevent
+ loops.
+ [Graham Leggett ]
+
+ *) Fix warnings about byte count type on Darwin (connect handler).
+ [Chuck Murcko ]
+
+ *) IPV6 EPSV support for IPV6 in FTP proxy.
+ [Graham Leggett ]
+
+ *) FTP directory filter works now.
+ [Graham Leggett ]
+
+ *) Fixed some thread-safety issues with the HTTP proxy in mod_proxy.
+ [Graham Leggett ]
+
+ *) PASV FTP works now.
+ [Graham Leggett ]
+
+ *) Reworked the line-at-a-time read from the control connection to
+ workaround a stray empty bucket returned by the HTTP_IN filter.
+ [Graham Leggett ]
+
+ *) Stopped the CORE filter from sending off an HTTP response when a
+ CONNECT tunnel was closed.
+ [Graham Leggett ]
+
+ *) Fixed the poll() loop in proxy_connect.c -> it works now!!!
+ [Graham Leggett ]
+
+ *) Converted send_dir() to ap_proxy_send_dir_filter() in proxy_ftp.c.
+ [Graham Leggett ]
+
+ *) Major rework of ap_proxy_ftp_handler() to use filters (begone foul
+ BUFF!!!). It compiles, but is untested, and the build environment needs
+ to be fixed to include proxy_ftp.c.
+ [Graham Leggett ]
+
+ *) Cleanup of dead functions within proxy_util.c.
+ [Graham Leggett ]
+
+ *) Reworked the storage of the client socket between keepalive connections
+ to fix some nasty problems with the socket lasting longer than the
+ memory pool it was allocated from.
+ [Graham Leggett ]
+
+ *) Fixed bug where a hostname without a "." in it (such as "localhost")
+ would not trigger an IP address check with ProxyBlock.
+ [Graham Leggett ]
+
+ *) Fixed ProxyBlock bugs with ap_proxy_http_handler() and
+ ap_proxy_connect_handler().
+ [Graham Leggett ]
+
+ *) Updated ap_proxy_connect_handler() to support APR, while
+ moving some common code between http_handler and connect_handler
+ to proxy_util.c.
+ [Graham Leggett ]
+
+ *) Updated mod_proxy.html docs to include v2.0 configuration.
+ [Graham Leggett ]
+
+ *) Fixed problem where responses without entity bodies would cause
+ the directly following proxy keepalive request to fail.
+ [Graham Leggett ]
+
+ *) Added support for downstream keepalives in mod_proxy.
+ [Graham Leggett ]
+
+ *) Changed mod_proxy ap_proxy_http_handler() to support APR properly.
+ [Graham Leggett ]
+
+ *) Fix problem where incoming response headers were not being returned
+ to the client in mod_proxy.
+ [Graham Leggett ]
+
+ *) Added X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Server to
+ reverse proxied request headers in mod_proxy.
+ [Graham Leggett ]
+
+ *) replace INADDR_NONE with APR_INADDR_NONE [Ian Holsman ]
+
+ *) Fix problem with proxy configuration where globally set
+ configuration options were overridden inside virtual hosts.
+ [Graham Leggett ]
+
+ *) Fix ProxyReceiveBufferSize where default value was left
+ uninitialised.
+ [Graham Leggett ]
+
+ *) Some small changes:
+ - Ensured hop-by-hop headers were stripped as per
+ RFC2616 13.5.1.
+ - Upgraded version code to HTTP/1.1.
+ - Added Connection: close until Keepalives come.
+ - Some cosmetic fixes and commenting.
+ [Graham Leggett ]
+
+mod_proxy changes for 2.0.14 alpha
+
+ *) removed ProxyNoCache and ProxyCacheForceCompletion config directives,
+ since we no longer directly cache from this module [Chuck Murcko]
+
+ *) removed cache [Chuck Murcko]
+
+ *) initial rerebuild for 2.0 [Chuck Murcko]
+
diff --git a/modules/ssl/Makefile.in b/modules/ssl/Makefile.in
new file mode 100644
index 00000000000..2207d48f3c4
--- /dev/null
+++ b/modules/ssl/Makefile.in
@@ -0,0 +1,50 @@
+## ====================================================================
+## The Apache Software License, Version 1.1
+##
+## Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+## reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+## 1. Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## 2. Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+##
+## 3. The end-user documentation included with the redistribution,
+## if any, must include the following acknowledgment:
+## "This product includes software developed by the
+## Apache Software Foundation (http://www.apache.org/)."
+## Alternately, this acknowledgment may appear in the software itself,
+## if and wherever such third-party acknowledgments normally appear.
+##
+## 4. The names "Apache" and "Apache Software Foundation" must
+## not be used to endorse or promote products derived from this
+## software without prior written permission. For written
+## permission, please contact apache@apache.org.
+##
+## 5. Products derived from this software may not be called "Apache",
+## nor may "Apache" appear in their name, without prior written
+## permission of the Apache Software Foundation.
+##
+## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+## OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+## DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+## ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+## SUCH DAMAGE.
+## ====================================================================
+
+include $(top_srcdir)/build/special.mk
+
diff --git a/modules/ssl/config.m4 b/modules/ssl/config.m4
new file mode 100644
index 00000000000..4eeefd7b797
--- /dev/null
+++ b/modules/ssl/config.m4
@@ -0,0 +1,160 @@
+dnl ## ====================================================================
+dnl ## The Apache Software License, Version 1.1
+dnl ##
+dnl ## Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+dnl ## reserved.
+dnl ##
+dnl ## Redistribution and use in source and binary forms, with or without
+dnl ## modification, are permitted provided that the following conditions
+dnl ## are met:
+dnl ##
+dnl ## 1. Redistributions of source code must retain the above copyright
+dnl ## notice, this list of conditions and the following disclaimer.
+dnl ##
+dnl ## 2. Redistributions in binary form must reproduce the above copyright
+dnl ## notice, this list of conditions and the following disclaimer in
+dnl ## the documentation and/or other materials provided with the
+dnl ## distribution.
+dnl ##
+dnl ## 3. The end-user documentation included with the redistribution,
+dnl ## if any, must include the following acknowledgment:
+dnl ## "This product includes software developed by the
+dnl ## Apache Software Foundation (http://www.apache.org/)."
+dnl ## Alternately, this acknowledgment may appear in the software itself,
+dnl ## if and wherever such third-party acknowledgments normally appear.
+dnl ##
+dnl ## 4. The names "Apache" and "Apache Software Foundation" must
+dnl ## not be used to endorse or promote products derived from this
+dnl ## software without prior written permission. For written
+dnl ## permission, please contact apache@apache.org.
+dnl ##
+dnl ## 5. Products derived from this software may not be called "Apache",
+dnl ## nor may "Apache" appear in their name, without prior written
+dnl ## permission of the Apache Software Foundation.
+dnl ##
+dnl ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+dnl ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+dnl ## OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+dnl ## DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+dnl ## ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+dnl ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+dnl ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+dnl ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+dnl ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+dnl ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+dnl ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+dnl ## SUCH DAMAGE.
+dnl ## ====================================================================
+
+dnl # start of module specific part
+APACHE_MODPATH_INIT(ssl)
+
+dnl # list of module object files
+ssl_objs="mod_ssl.lo"
+ssl_objs="$ssl_objs ssl_engine_config.lo"
+
+dnl # hook module into the Autoconf mechanism (--enable-ssl option)
+APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [
+
+ dnl # hook into Autoconf mechanism (--with-ssl[=DIR] option)
+ AC_MSG_CHECKING(for SSL/TLS toolkit base)
+ ssltk_base="SYSTEM"
+ AC_ARG_WITH(ssl, [ --with-ssl[=DIR] SSL/TLS toolkit (OpenSSL)], [
+ if test ".$withval" != .yes -a ".$withval" != .; then
+ ssltk_base="$withval"
+ if test ! -d $ssltk_base; then
+ AC_MSG_ERROR([invalid SSL/TLS toolkit base directory $ssltk_base])
+ fi
+ fi
+ ])
+ AC_MSG_RESULT($ssltk_base)
+
+ dnl # determine SSL/TLS toolkit frontend (openssl binary)
+ AC_MSG_CHECKING(for SSL/TLS toolkit frontend)
+ ssltk_frontend=""
+ if test ".$ssltk_base" = .SYSTEM; then
+ for p in . `echo $PATH | sed -e 's/:/ /g'`; do
+ if test -f "$p/openssl"; then
+ ssltk_frontend="$p/openssl"
+ break
+ fi
+ done
+ if test ".$ssltk_frontend" = .; then
+ AC_MSG_ERROR(['openssl' not found in $PATH])
+ fi
+ else
+ if test -f "$ssltk_base/bin/openssl"; then
+ ssltk_frontend="$ssltk_base/bin/openssl"
+ else
+ AC_MSG_ERROR(['openssl' not found in $ssltk_base/bin/])
+ fi
+ fi
+ AC_MSG_RESULT($ssltk_frontend)
+
+ dnl # determine SSL/TLS toolkit version
+ AC_MSG_CHECKING(for SSL/TLS toolkit version)
+ ssltk_version="`$ssltk_frontend version`"
+ case "$ssltk_version" in
+ *0.9.[[6789]]* ) ;;
+ * ) AC_MSG_ERROR([SSL/TLS toolkit version $ssltk_version not supported]) ;;
+ esac
+ AC_MSG_RESULT($ssltk_version)
+
+ dnl # determine SSL/TLS toolkit include directory
+ AC_MSG_CHECKING(for SSL/TLS toolkit includes)
+ ssltk_incdir=""
+ if test ".$ssltk_base" = .SYSTEM; then
+ for p in . /usr/include /usr/include/ssl/ /usr/local/include /usr/local/include/ssl; do
+ if test -f "$p/openssl/ssl.h"; then
+ ssltk_incdir="$p"
+ break
+ fi
+ done
+ if test ".$ssltk_incdir" = .; then
+ AC_MSG_ERROR([OpenSSL headers not found])
+ fi
+ else
+ if test -f "$ssltk_base/include/openssl/ssl.h"; then
+ ssltk_incdir="$ssltk_base/include"
+ else
+ AC_MSG_ERROR([OpenSSL headers not found under $ssltk_base])
+ fi
+ fi
+ AC_MSG_RESULT($ssltk_incdir)
+
+ dnl # determine SSL/TLS toolkit library directory
+ AC_MSG_CHECKING(for SSL/TLS toolkit libraries)
+ ssltk_libdir=""
+ if test ".$ssltk_base" = .SYSTEM; then
+ for p in . /lib /usr/lib /usr/local/lib; do
+ if test -f "$p/libssl.a" -o -f "$p/libssl.so"; then
+ ssltk_libdir="$p"
+ break
+ fi
+ done
+ if test ".$ssltk_libdir" = .; then
+ AC_MSG_ERROR([OpenSSL libraries not found])
+ fi
+ else
+ if test -f "$ssltk_base/libssl.a" -o -f "$ssltk_base/libssl.so"; then
+ ssltk_libdir="$ssltk_base"
+ elif test -f "$ssltk_base/lib/libssl.a" -o -f "$ssltk_base/lib/libssl.so"; then
+ ssltk_libdir="$ssltk_base/lib"
+ else
+ AC_MSG_ERROR([OpenSSL libraries not found under $ssltk_base])
+ fi
+ fi
+ AC_MSG_RESULT($ssltk_libdir)
+
+ dnl # annotate the Apache build environment with determined information
+ if test ".$ssltk_incdir" != "./usr/include"; then
+ INCLUDES="$INCLUDES -I$ssltk_incdir"
+ fi
+ if test ".$ssltk_libdir" != "./usr/lib"; then
+ LIBS="$LIBS -L$ssltk_libdir -lssl -lcrypto"
+ fi
+])
+
+dnl # end of module specific part
+APACHE_MODPATH_FINISH
+
diff --git a/modules/ssl/mod_ssl.dsp b/modules/ssl/mod_ssl.dsp
new file mode 100644
index 00000000000..c1f46dfb836
--- /dev/null
+++ b/modules/ssl/mod_ssl.dsp
@@ -0,0 +1,217 @@
+# Microsoft Developer Studio Project File - Name="mod_ssl" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_ssl - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_ssl.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_ssl.mak" CFG="mod_ssl - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_ssl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_ssl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_ssl - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\os\win32" /I "..\..\server\mpm\winnt" /I "..\..\srclib\apr\include" /I "../../srclib/apr-util/include" /I "..\..\srclib\openssl\inc32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_ssl" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /out:"Release/mod_ssl.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_ssl
+# ADD LINK32 kernel32.lib ssleay32.lib libeay32.lib /nologo /libpath:"..\..\srclib\openssl\out32dll" /subsystem:windows /dll /incremental:no /map /out:"Release/mod_ssl.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_ssl
+
+!ELSEIF "$(CFG)" == "mod_ssl - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\..\include" /I "..\..\os\win32" /I "..\..\server\mpm\winnt" /I "..\..\srclib\apr\include" /I "..\..\srclib\apr-util\include" /I "..\..\srclib\openssl\inc32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_ssl" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_ssl.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_ssl
+# ADD LINK32 kernel32.lib ssleay32.lib libeay32.lib /nologo /libpath:"..\..\srclib\openssl\out32dll" /subsystem:windows /dll /incremental:no /map /debug /out:"Debug/mod_ssl.so" /machine:I386 /base:@..\..\os\win32\BaseAddr.ref,mod_ssl
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_ssl - Win32 Release"
+# Name "mod_ssl - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\mod_ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_config.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_dh.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_ds.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_ext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_init.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_io.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_kernel.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_mutex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_pphrase.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_rand.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_engine_vars.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr_eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr_parse.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr_scan.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_scache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_scache_dbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_scache_shmcb.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_scache_shmht.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_util_ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_util_table.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "*.h"
+# Begin Source File
+
+SOURCE=.\mod_ssl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_expr_parse.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_util_ssl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ssl_util_table.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/modules/test/Makefile.in b/modules/test/Makefile.in
new file mode 100644
index 00000000000..7c5c149d852
--- /dev/null
+++ b/modules/test/Makefile.in
@@ -0,0 +1,3 @@
+# a modules Makefile has no explicit targets -- they will be defined by
+# whatever modules are enabled. just grab special.mk to deal with this.
+include $(top_srcdir)/build/special.mk
diff --git a/modules/test/config.m4 b/modules/test/config.m4
new file mode 100644
index 00000000000..01bc0fa9717
--- /dev/null
+++ b/modules/test/config.m4
@@ -0,0 +1,9 @@
+
+APACHE_MODPATH_INIT(test)
+
+APACHE_MODULE(optional_hook_export, example optional hook exporter, , , no)
+APACHE_MODULE(optional_hook_import, example optional hook importer, , , no)
+APACHE_MODULE(optional_fn_import, example optional function importer, , , no)
+APACHE_MODULE(optional_fn_export, example optional function exporter, , , no)
+
+APACHE_MODPATH_FINISH
diff --git a/modules/test/mod_optional_hook_export.c b/modules/test/mod_optional_hook_export.c
new file mode 100644
index 00000000000..34ef97b543a
--- /dev/null
+++ b/modules/test/mod_optional_hook_export.c
@@ -0,0 +1,83 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "mod_optional_hook_export.h"
+#include "http_protocol.h"
+
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap,AP_MODULE,int,generic_hook_test,
+ (const char *szStr),
+ (szStr),OK,DECLINED)
+
+static int ExportLogTransaction(request_rec *r)
+{
+ return ap_run_generic_hook_test(r->the_request);
+}
+
+static void ExportRegisterHooks(apr_pool_t *p)
+{
+ ap_hook_log_transaction(ExportLogTransaction,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+module optional_hook_export_module =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ExportRegisterHooks
+};
diff --git a/modules/test/mod_optional_hook_export.h b/modules/test/mod_optional_hook_export.h
new file mode 100644
index 00000000000..7494078cdd2
--- /dev/null
+++ b/modules/test/mod_optional_hook_export.h
@@ -0,0 +1,62 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+#ifndef MOD_GENERIC_HOOK_EXPORT_H
+#define MOD_GENERIC_HOOK_EXPORT_H
+
+#include "apr_optional_hooks.h"
+
+APR_DECLARE_EXTERNAL_HOOK(ap,AP_MODULE,int,generic_hook_test,(const char *))
+
+#endif /* def MOD_GENERIC_HOOK_EXPORT_H */
diff --git a/modules/test/mod_optional_hook_import.c b/modules/test/mod_optional_hook_import.c
new file mode 100644
index 00000000000..ebf01586108
--- /dev/null
+++ b/modules/test/mod_optional_hook_import.c
@@ -0,0 +1,83 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "mod_optional_hook_export.h"
+
+static int ImportGenericHookTestHook(const char *szStr)
+{
+ ap_log_error(APLOG_MARK,APLOG_ERR,OK,NULL,"Generic hook test said: %s",
+ szStr);
+
+ return OK;
+}
+
+static void ImportRegisterHooks(apr_pool_t *p)
+{
+ APR_OPTIONAL_HOOK(ap,generic_hook_test,ImportGenericHookTestHook,NULL,NULL,
+ APR_HOOK_MIDDLE);
+}
+
+module optional_hook_import_module=
+{
+ STANDARD20_MODULE_STUFF,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ImportRegisterHooks
+};
diff --git a/server/mpm/mpmt_os2/.cvsignore b/server/mpm/mpmt_os2/.cvsignore
new file mode 100644
index 00000000000..dc53ac865db
--- /dev/null
+++ b/server/mpm/mpmt_os2/.cvsignore
@@ -0,0 +1,5 @@
+*.lo
+*.la
+Makefile
+.deps
+.libs
diff --git a/server/mpm/mpmt_os2/Makefile.in b/server/mpm/mpmt_os2/Makefile.in
new file mode 100644
index 00000000000..38e598edf3a
--- /dev/null
+++ b/server/mpm/mpmt_os2/Makefile.in
@@ -0,0 +1,5 @@
+
+LTLIBRARY_NAME = libmpmt_os2.la
+LTLIBRARY_SOURCES = mpmt_os2.c mpmt_os2_child.c
+
+include $(top_srcdir)/build/ltlib.mk
diff --git a/server/mpm/mpmt_os2/config5.m4 b/server/mpm/mpmt_os2/config5.m4
new file mode 100644
index 00000000000..b27c296d2a4
--- /dev/null
+++ b/server/mpm/mpmt_os2/config5.m4
@@ -0,0 +1,5 @@
+if test "$MPM_NAME" = "mpmt_os2" ; then
+ AC_CACHE_SAVE
+ APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
+ APR_ADDTO(CFLAGS,-Zmt)
+fi
diff --git a/server/mpm/mpmt_os2/mpm.h b/server/mpm/mpmt_os2/mpm.h
new file mode 100644
index 00000000000..37d2f6c20c4
--- /dev/null
+++ b/server/mpm/mpmt_os2/mpm.h
@@ -0,0 +1,74 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef APACHE_MPM_MPMT_OS2_H
+#define APACHE_MPM_MPMT_OS2_H
+
+#define MPMT_OS2_MPM
+
+#include "httpd.h"
+#include "mpm_default.h"
+#include "scoreboard.h"
+
+#define MPM_NAME "MPMT_OS2"
+
+extern server_rec *ap_server_conf;
+#define AP_MPM_WANT_SET_PIDFILE
+#define AP_MPM_WANT_SET_MAX_REQUESTS
+
+#endif /* APACHE_MPM_SPMT_OS2_H */
diff --git a/server/mpm/mpmt_os2/mpm_default.h b/server/mpm/mpmt_os2/mpm_default.h
new file mode 100644
index 00000000000..100beb2e61f
--- /dev/null
+++ b/server/mpm/mpmt_os2/mpm_default.h
@@ -0,0 +1,116 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef APACHE_MPM_DEFAULT_H
+#define APACHE_MPM_DEFAULT_H
+
+/* Number of servers processes to spawn off by default
+ */
+#ifndef DEFAULT_START_DAEMON
+#define DEFAULT_START_DAEMON 2
+#endif
+
+/* We don't need many processes,
+ * they're only for redundancy in the event of a crash
+ */
+#define HARD_SERVER_LIMIT 10
+
+/* Limit on the total number of threads per process
+ */
+#ifndef HARD_THREAD_LIMIT
+#define HARD_THREAD_LIMIT 256
+#endif
+
+/* Maximum number of *free* server threads --- more than this, and
+ * they will die off.
+ */
+
+#ifndef DEFAULT_MAX_SPARE_THREAD
+#define DEFAULT_MAX_SPARE_THREAD 10
+#endif
+
+/* Minimum --- fewer than this, and more will be created */
+
+#ifndef DEFAULT_MIN_SPARE_THREAD
+#define DEFAULT_MIN_SPARE_THREAD 5
+#endif
+
+/* Where the main/parent process's pid is logged */
+#ifndef DEFAULT_PIDLOG
+#define DEFAULT_PIDLOG "logs/httpd.pid"
+#endif
+
+/*
+ * Interval, in microseconds, between scoreboard maintenance.
+ */
+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
+#endif
+
+/* Number of requests to try to handle in a single process. If <= 0,
+ * the children don't die off.
+ */
+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
+#endif
+
+/* AP_CHILD_THREAD_FROM_ID is used by the scoreboard. */
+#define AP_CHILD_THREAD_FROM_ID(i) (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT)
+#define AP_ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t)
+
+#endif /* AP_MPM_DEFAULT_H */
diff --git a/server/mpm/mpmt_os2/mpmt_os2.c b/server/mpm/mpmt_os2/mpmt_os2.c
new file mode 100644
index 00000000000..99806d1c8eb
--- /dev/null
+++ b/server/mpm/mpmt_os2/mpmt_os2.c
@@ -0,0 +1,587 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/* Multi-process, multi-threaded MPM for OS/2
+ *
+ * Server consists of
+ * - a main, parent process
+ * - a small, static number of child processes
+ *
+ * The parent process's job is to manage the child processes. This involves
+ * spawning children as required to ensure there are always ap_daemons_to_start
+ * processes accepting connections.
+ *
+ * Each child process consists of a a pool of worker threads and a
+ * main thread that accepts connections & passes them to the workers via
+ * a work queue. The worker thread pool is dynamic, managed by a maintanence
+ * thread so that the number of idle threads is kept between
+ * min_spare_threads & max_spare_threads.
+ *
+ */
+
+/*
+ Todo list
+ - Fix log file clashing between child processes
+ - Enforce MaxClients somehow
+ - Catch thread exceptions & initiate graceful shutdown of child process
+*/
+#define CORE_PRIVATE
+#define INCL_NOPMAPI
+#define INCL_DOS
+#define INCL_DOSERRORS
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "mpm_default.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h"
+#include "http_core.h" /* for get_remote_host */
+#include "http_connection.h"
+#include "mpm.h"
+#include "ap_mpm.h"
+#include "ap_listen.h"
+#include "apr_portable.h"
+#include "mpm_common.h"
+#include "apr_strings.h"
+#include
+#include
+
+server_rec *ap_server_conf;
+static apr_pool_t *pconf = NULL; /* Pool for config stuff */
+static const char *ap_pid_fname=NULL;
+
+/* Config globals */
+static int one_process = 0;
+static int ap_daemons_to_start = 0;
+static int ap_thread_limit = 0;
+static int ap_max_requests_per_child = 0;
+int ap_min_spare_threads = 0;
+int ap_max_spare_threads = 0;
+
+/* Keep track of a few interesting statistics */
+int ap_max_daemons_limit = -1;
+
+/* volatile just in case */
+static int volatile shutdown_pending;
+static int volatile restart_pending;
+static int volatile is_graceful = 0;
+ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */
+static int is_parent_process=TRUE;
+HMTX ap_mpm_accept_mutex = 0;
+
+/* An array of these is stored in a shared memory area for passing
+ * sockets from the parent to child processes
+ */
+typedef struct {
+ struct sockaddr_in name;
+ apr_os_sock_t listen_fd;
+} listen_socket_t;
+
+typedef struct {
+ apr_os_file_t errorlog_fd;
+ apr_time_t restart_time;
+ HMTX accept_mutex;
+ listen_socket_t listeners[1];
+} parent_info_t;
+
+static char master_main();
+static void spawn_child(int slot);
+void ap_mpm_child_main(apr_pool_t *pconf);
+static void set_signals();
+
+
+int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
+{
+ char *listener_shm_name;
+ parent_info_t *parent_info;
+ ULONG rc;
+ pconf = _pconf;
+ ap_server_conf = s;
+ restart_pending = 0;
+
+ DosSetMaxFH(ap_thread_limit * 2);
+ listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getppid());
+ rc = DosGetNamedSharedMem((PPVOID)&parent_info, listener_shm_name, PAG_READ);
+ is_parent_process = rc != 0;
+ ap_scoreboard_fname = apr_psprintf(pconf, "/sharemem/httpd/scoreboard.%d", is_parent_process ? getpid() : getppid());
+
+ if (rc == 0) {
+ /* Child process */
+ ap_listen_rec *lr;
+ int num_listeners = 0;
+
+ apr_file_close(ap_server_conf->error_log);
+ apr_os_file_put(&ap_server_conf->error_log, &parent_info->errorlog_fd, pconf);
+ ap_restart_time = parent_info->restart_time;
+ ap_mpm_accept_mutex = parent_info->accept_mutex;
+
+ /* Set up a default listener if necessary */
+ if (ap_listeners == NULL) {
+ ap_listen_rec *lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
+ ap_listeners = lr;
+ apr_sockaddr_info_get(&lr->bind_addr, "0.0.0.0", APR_UNSPEC,
+ DEFAULT_HTTP_PORT, 0, s->process->pool);
+ apr_socket_create(&lr->sd, lr->bind_addr->sa.sin.sin_family,
+ SOCK_STREAM, s->process->pool);
+ }
+
+ for (lr = ap_listeners; lr; lr = lr->next) {
+ apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf);
+ num_listeners++;
+ }
+
+ DosFreeMem(parent_info);
+
+ /* Do the work */
+ ap_mpm_child_main(pconf);
+
+ /* Outta here */
+ return 1;
+ }
+ else {
+ /* Parent process */
+ char restart;
+ is_parent_process = TRUE;
+ ap_log_pid(pconf, ap_pid_fname);
+
+ if (ap_setup_listeners(ap_server_conf) < 1) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
+ "no listening sockets available, shutting down");
+ return 1;
+ }
+
+ restart = master_main();
+ ++ap_my_generation;
+ ap_scoreboard_image->global.running_generation = ap_my_generation;
+
+ if (!restart) {
+ const char *pidfile = ap_server_root_relative(pconf, ap_pid_fname);
+
+ if (pidfile != NULL && remove(pidfile) == 0) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS,
+ ap_server_conf, "removed PID file %s (pid=%d)",
+ pidfile, getpid());
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "caught SIGTERM, shutting down");
+ return 1;
+ }
+ } /* Parent process */
+
+ return 0; /* Restart */
+}
+
+
+
+/* Main processing of the parent process
+ * returns TRUE if restarting
+ */
+static char master_main()
+{
+ server_rec *s = ap_server_conf;
+ ap_listen_rec *lr;
+ parent_info_t *parent_info;
+ char *listener_shm_name;
+ int listener_num, num_listeners, slot;
+ ULONG rc;
+
+ printf("%s \n", ap_get_server_version());
+ set_signals();
+
+ if (ap_setup_listeners(ap_server_conf) < 1) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
+ "no listening sockets available, shutting down");
+ return FALSE;
+ }
+
+ /* Allocate a shared memory block for the array of listeners */
+ for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) {
+ num_listeners++;
+ }
+
+ listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getpid());
+ rc = DosAllocSharedMem((PPVOID)&parent_info, listener_shm_name,
+ sizeof(parent_info_t) + num_listeners * sizeof(listen_socket_t),
+ PAG_READ|PAG_WRITE|PAG_COMMIT);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
+ "failure allocating shared memory, shutting down");
+ return FALSE;
+ }
+
+ /* Store the listener sockets in the shared memory area for our children to see */
+ for (listener_num = 0, lr = ap_listeners; lr; lr = lr->next, listener_num++) {
+ apr_os_sock_get(&parent_info->listeners[listener_num].listen_fd, lr->sd);
+ }
+
+ /* Create mutex to prevent multiple child processes from detecting
+ * a connection with apr_poll()
+ */
+
+ rc = DosCreateMutexSem(NULL, &ap_mpm_accept_mutex, DC_SEM_SHARED, FALSE);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
+ "failure creating accept mutex, shutting down");
+ return FALSE;
+ }
+
+ ap_restart_time = apr_time_now();
+ parent_info->restart_time = ap_restart_time;
+ parent_info->accept_mutex = ap_mpm_accept_mutex;
+ apr_os_file_get(&parent_info->errorlog_fd, s->error_log);
+
+ /* Allocate shared memory for scoreboard */
+ if (ap_scoreboard_image == NULL) {
+ rc = DosAllocSharedMem((PPVOID)&ap_scoreboard_image, ap_scoreboard_fname,
+ sizeof(scoreboard), PAG_COMMIT|PAG_READ|PAG_WRITE);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "unable to allocate shared memory for scoreboard , exiting");
+ return FALSE;
+ }
+
+ memset(ap_scoreboard_image, 0, sizeof(scoreboard));
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "%s configured -- resuming normal operations",
+ ap_get_server_version());
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
+ "Server built: %s", ap_get_server_built());
+
+ if (one_process) {
+ ap_scoreboard_image->parent[0].pid = getpid();
+ ap_mpm_child_main(pconf);
+ return FALSE;
+ }
+
+ while (!restart_pending && !shutdown_pending) {
+ RESULTCODES proc_rc;
+ PID child_pid;
+ int active_children = 0;
+
+ /* Count number of active children */
+ for (slot=0; slot < HARD_SERVER_LIMIT; slot++) {
+ active_children += ap_scoreboard_image->parent[slot].pid != 0 &&
+ !ap_scoreboard_image->parent[slot].quiescing;
+ }
+
+ /* Spawn children if needed */
+ for (slot=0; slot < HARD_SERVER_LIMIT && active_children < ap_daemons_to_start; slot++) {
+ if (ap_scoreboard_image->parent[slot].pid == 0) {
+ spawn_child(slot);
+ active_children++;
+ }
+ }
+
+ rc = DosWaitChild(DCWA_PROCESSTREE, DCWW_NOWAIT, &proc_rc, &child_pid, 0);
+
+ if (rc == 0) {
+ /* A child has terminated, remove its scoreboard entry & terminate if necessary */
+ for (slot=0; ap_scoreboard_image->parent[slot].pid != child_pid && slot < HARD_SERVER_LIMIT; slot++);
+
+ if (slot < HARD_SERVER_LIMIT) {
+ ap_scoreboard_image->parent[slot].pid = 0;
+ ap_scoreboard_image->parent[slot].quiescing = 0;
+
+ if (proc_rc.codeTerminate == TC_EXIT) {
+ /* Child terminated normally, check its exit code and
+ * terminate server if child indicates a fatal error
+ */
+ if (proc_rc.codeResult == APEXIT_CHILDFATAL)
+ break;
+ }
+ }
+ } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
+ /* No child exited, lets sleep for a while.... */
+ apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
+ }
+ }
+
+ /* Signal children to shut down, either gracefully or immediately */
+ for (slot=0; slotparent[slot].pid, is_graceful ? SIGHUP : SIGTERM);
+ }
+
+ DosFreeMem(parent_info);
+ return restart_pending;
+}
+
+
+
+static void spawn_child(int slot)
+{
+ PPIB ppib;
+ PTIB ptib;
+ char fail_module[100];
+ char progname[CCHMAXPATH];
+ RESULTCODES proc_rc;
+ ULONG rc;
+
+ ap_scoreboard_image->parent[slot].generation = ap_my_generation;
+ DosGetInfoBlocks(&ptib, &ppib);
+ DosQueryModuleName(ppib->pib_hmte, sizeof(progname), progname);
+ rc = DosExecPgm(fail_module, sizeof(fail_module), EXEC_ASYNCRESULT,
+ ppib->pib_pchcmd, NULL, &proc_rc, progname);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "error spawning child, slot %d", slot);
+ }
+
+ if (ap_max_daemons_limit < slot) {
+ ap_max_daemons_limit = slot;
+ }
+
+ ap_scoreboard_image->parent[slot].pid = proc_rc.codeTerminate;
+}
+
+
+
+/* Signal handling routines */
+
+static void sig_term(int sig)
+{
+ shutdown_pending = 1;
+}
+
+
+
+static void sig_restart(int sig)
+{
+ if (sig == SIGUSR1) {
+ is_graceful = 1;
+ }
+
+ restart_pending = 1;
+}
+
+
+
+static void set_signals()
+{
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = sig_term;
+
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
+
+ if (sigaction(SIGINT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
+
+ sa.sa_handler = sig_restart;
+
+ if (sigaction(SIGHUP, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
+ if (sigaction(SIGUSR1, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGUSR1)");
+}
+
+
+
+/* Enquiry functions used get MPM status info */
+
+AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
+{
+ switch (query_code) {
+ case AP_MPMQ_MAX_DAEMON_USED:
+ *result = ap_max_daemons_limit;
+ return APR_SUCCESS;
+ case AP_MPMQ_IS_THREADED:
+ *result = AP_MPMQ_DYNAMIC;
+ return APR_SUCCESS;
+ case AP_MPMQ_IS_FORKED:
+ *result = AP_MPMQ_NOT_SUPPORTED;
+ return APR_SUCCESS;
+ case AP_MPMQ_HARD_LIMIT_DAEMONS:
+ *result = HARD_SERVER_LIMIT;
+ return APR_SUCCESS;
+ case AP_MPMQ_HARD_LIMIT_THREADS:
+ *result = HARD_THREAD_LIMIT;
+ return APR_SUCCESS;
+ case AP_MPMQ_MIN_SPARE_DEAMONS:
+ *result = 0;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_SPARE_DAEMONS:
+ *result = 0;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_REQUESTS_DEAMON:
+ *result = ap_max_requests_per_child;
+ return APR_SUCCESS;
+ }
+ return APR_ENOTIMPL;
+}
+
+
+
+int ap_graceful_stop_signalled(void)
+{
+ return is_graceful;
+}
+
+
+
+/* Configuration handling stuff */
+
+static void mpmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ one_process = !!ap_exists_config_define("ONE_PROCESS");
+ is_graceful = 0;
+ ap_listen_pre_config();
+ ap_daemons_to_start = DEFAULT_START_DAEMON;
+ ap_thread_limit = HARD_THREAD_LIMIT;
+ ap_pid_fname = DEFAULT_PIDLOG;
+ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
+ ap_extended_status = 0;
+ ap_min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
+ ap_max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
+}
+
+
+
+static void mpmt_os2_hooks(apr_pool_t *p)
+{
+ ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+
+
+static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_daemons_to_start = atoi(arg);
+ return NULL;
+}
+
+
+
+static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_min_spare_threads = atoi(arg);
+
+ if (ap_min_spare_threads <= 0) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "WARNING: detected MinSpareThreads set to non-positive.");
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "Resetting to 1 to avoid almost certain Apache failure.");
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "Please read the documentation.");
+ ap_min_spare_threads = 1;
+ }
+
+ return NULL;
+}
+
+
+
+static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_max_spare_threads = atoi(arg);
+ return NULL;
+}
+
+
+
+static const command_rec mpmt_os2_cmds[] = {
+LISTEN_COMMANDS
+AP_INIT_TAKE1( "StartServers", set_daemons_to_start, NULL, RSRC_CONF,
+ "Number of child processes launched at server startup" ),
+AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
+ "Minimum number of idle children, to handle request spikes"),
+AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
+ "Maximum number of idle children"),
+{ NULL }
+};
+
+module AP_MODULE_DECLARE_DATA mpm_mpmt_os2_module = {
+ MPM20_MODULE_STUFF,
+ NULL, /* hook to run before apache parses args */
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ mpmt_os2_cmds, /* command apr_table_t */
+ mpmt_os2_hooks, /* register_hooks */
+};
diff --git a/server/mpm/mpmt_os2/mpmt_os2_child.c b/server/mpm/mpmt_os2/mpmt_os2_child.c
new file mode 100644
index 00000000000..36a96ca939c
--- /dev/null
+++ b/server/mpm/mpmt_os2/mpmt_os2_child.c
@@ -0,0 +1,463 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#define CORE_PRIVATE
+#define INCL_NOPMAPI
+#define INCL_DOS
+#define INCL_DOSERRORS
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "mpm_default.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h"
+#include "http_core.h" /* for get_remote_host */
+#include "http_connection.h"
+#include "mpm.h"
+#include "ap_mpm.h"
+#include "ap_listen.h"
+#include "apr_portable.h"
+#include "mpm_common.h"
+#include "apr_strings.h"
+#include
+#include
+
+typedef struct {
+ apr_pool_t *pconn;
+ apr_socket_t *conn_sd;
+} worker_args_t;
+
+#define WORKTYPE_CONN 0
+#define WORKTYPE_EXIT 1
+
+static apr_pool_t *pchild = NULL;
+static int child_slot;
+static int shutdown_pending = 0;
+extern int ap_my_generation;
+static int volatile is_graceful = 1;
+HEV shutdown_event; /* signaled when this child is shutting down */
+
+/* grab some MPM globals */
+extern int ap_min_spare_threads;
+extern int ap_max_spare_threads;
+extern HMTX ap_mpm_accept_mutex;
+
+static void worker_main(void *vpArg);
+static void clean_child_exit(int code);
+static void set_signals();
+static void server_maintenance(void *vpArg);
+
+
+static void clean_child_exit(int code)
+{
+ if (pchild) {
+ apr_pool_destroy(pchild);
+ }
+
+ exit(code);
+}
+
+
+
+void ap_mpm_child_main(apr_pool_t *pconf)
+{
+ ap_listen_rec *lr = NULL;
+ ap_listen_rec *first_lr = NULL;
+ int requests_this_child = 0;
+ apr_socket_t *sd = ap_listeners->sd;
+ int nsds, rv = 0;
+ unsigned long ulTimes;
+ int my_pid = getpid();
+ ULONG rc, c;
+ HQUEUE workq;
+ apr_pollfd_t *pollset;
+ int num_listeners;
+ TID server_maint_tid;
+
+ /* Stop Ctrl-C/Ctrl-Break signals going to child processes */
+ DosSetSignalExceptionFocus(0, &ulTimes);
+ set_signals();
+
+ /* Create pool for child */
+ apr_pool_create(&pchild, pconf);
+
+ /* Create an event semaphore used to trigger other threads to shutdown */
+ rc = DosCreateEventSem(NULL, &shutdown_event, 0, FALSE);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "unable to create shutdown semaphore, exiting");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ /* Gain access to the scoreboard. */
+ rc = DosGetNamedSharedMem((PPVOID)&ap_scoreboard_image, ap_scoreboard_fname,
+ PAG_READ|PAG_WRITE);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "scoreboard not readable in child, exiting");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ /* Gain access to the accpet mutex */
+ rc = DosOpenMutexSem(NULL, &ap_mpm_accept_mutex);
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "accept mutex couldn't be accessed in child, exiting");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ /* Find our pid in the scoreboard so we know what slot our parent allocated us */
+ for (child_slot = 0; ap_scoreboard_image->parent[child_slot].pid != my_pid && child_slot < HARD_SERVER_LIMIT; child_slot++);
+
+ if (child_slot == HARD_SERVER_LIMIT) {
+ ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, ap_server_conf,
+ "child pid not found in scoreboard, exiting");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ ap_my_generation = ap_scoreboard_image->parent[child_slot].generation;
+
+ /* Set up an OS/2 queue for passing connections & termination requests
+ * to worker threads
+ */
+ rc = DosCreateQueue(&workq, QUE_FIFO, apr_psprintf(pchild, "/queues/httpd/work.%d", my_pid));
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "unable to create work queue, exiting");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ /* Create initial pool of worker threads */
+ for (c = 0; c < ap_min_spare_threads; c++) {
+// ap_scoreboard_image->servers[child_slot][c].tid = _beginthread(worker_main, NULL, 128*1024, (void *)c);
+ }
+
+ /* Start maintenance thread */
+ server_maint_tid = _beginthread(server_maintenance, NULL, 32768, NULL);
+
+ /* Set up poll */
+ for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) {
+ num_listeners++;
+ }
+
+ apr_poll_setup(&pollset, num_listeners, pchild);
+
+ for (lr = ap_listeners; lr; lr = lr->next) {
+ apr_poll_socket_add(pollset, lr->sd, APR_POLLIN);
+ }
+
+ /* Main connection accept loop */
+ do {
+ apr_pool_t *pconn;
+ worker_args_t *worker_args;
+
+ apr_pool_create(&pconn, pchild);
+ worker_args = apr_palloc(pconn, sizeof(worker_args_t));
+ worker_args->pconn = pconn;
+
+ if (num_listeners == 1) {
+ rv = apr_accept(&worker_args->conn_sd, ap_listeners->sd, pconn);
+ } else {
+ rc = DosRequestMutexSem(ap_mpm_accept_mutex, SEM_INDEFINITE_WAIT);
+
+ if (shutdown_pending) {
+ DosReleaseMutexSem(ap_mpm_accept_mutex);
+ break;
+ }
+
+ rv = APR_FROM_OS_ERROR(rc);
+
+ if (rv == APR_SUCCESS) {
+ rv = apr_poll(pollset, &nsds, -1);
+ DosReleaseMutexSem(ap_mpm_accept_mutex);
+ }
+
+ if (rv == APR_SUCCESS) {
+ if (first_lr == NULL) {
+ first_lr = ap_listeners;
+ }
+
+ lr = first_lr;
+
+ do {
+ apr_int16_t event;
+
+ apr_poll_revents_get(&event, lr->sd, pollset);
+
+ if (event == APR_POLLIN) {
+ apr_sockaddr_t *sa;
+ apr_port_t port;
+ apr_socket_addr_get(&sa, APR_LOCAL, lr->sd);
+ apr_sockaddr_port_get(&port, sa);
+ first_lr = lr->next;
+ break;
+ }
+ lr = lr->next;
+
+ if (!lr) {
+ lr = ap_listeners;
+ }
+ } while (lr != first_lr);
+
+ if (lr == first_lr) {
+ continue;
+ }
+
+ sd = lr->sd;
+ rv = apr_accept(&worker_args->conn_sd, sd, pconn);
+ }
+ }
+
+ if (rv != APR_SUCCESS) {
+ if (!APR_STATUS_IS_EINTR(rv)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
+ "apr_accept");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+ } else {
+ DosWriteQueue(workq, WORKTYPE_CONN, sizeof(worker_args_t), worker_args, 0);
+ requests_this_child++;
+ }
+
+ if (ap_max_requests_per_child != 0 && requests_this_child >= ap_max_requests_per_child)
+ break;
+ } while (!shutdown_pending && ap_my_generation == ap_scoreboard_image->global.running_generation);
+
+ ap_scoreboard_image->parent[child_slot].quiescing = 1;
+ DosPostEventSem(shutdown_event);
+ DosWaitThread(&server_maint_tid, DCWW_WAIT);
+
+ if (is_graceful) {
+ char someleft;
+
+ /* tell our worker threads to exit */
+ for (c=0; cservers[child_slot][c].status != SERVER_DEAD) {
+ DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0);
+ }
+ }
+
+ do {
+ someleft = 0;
+
+ for (c=0; cservers[child_slot][c].status != SERVER_DEAD) {
+ someleft = 1;
+ DosSleep(1000);
+ break;
+ }
+ }
+ } while (someleft);
+ } else {
+ DosPurgeQueue(workq);
+
+ for (c=0; cservers[child_slot][c].status != SERVER_DEAD) {
+ DosKillThread(ap_scoreboard_image->servers[child_slot][c].tid);
+ }
+ }
+ }
+
+ apr_pool_destroy(pchild);
+}
+
+
+
+void add_worker()
+{
+ int thread_slot;
+
+ /* Find a free thread slot */
+ for (thread_slot=0; thread_slot < HARD_THREAD_LIMIT; thread_slot++) {
+ if (ap_scoreboard_image->servers[child_slot][thread_slot].status == SERVER_DEAD) {
+ ap_scoreboard_image->servers[child_slot][thread_slot].status = SERVER_STARTING;
+ ap_scoreboard_image->servers[child_slot][thread_slot].tid =
+ _beginthread(worker_main, NULL, 128*1024, (void *)thread_slot);
+ break;
+ }
+ }
+}
+
+
+
+static void worker_main(void *vpArg)
+{
+ long conn_id;
+ conn_rec *current_conn;
+ apr_pool_t *pconn;
+ worker_args_t *worker_args;
+ HQUEUE workq;
+ PID owner;
+ int rc;
+ REQUESTDATA rd;
+ ULONG len;
+ BYTE priority;
+ int thread_slot = (int)vpArg;
+
+ rc = DosOpenQueue(&owner, &workq,
+ apr_psprintf(pchild, "/queues/httpd/work.%d", getpid()));
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "unable to open work queue, exiting");
+ ap_scoreboard_image->servers[child_slot][thread_slot].tid = 0;
+ }
+
+ conn_id = AP_ID_FROM_CHILD_THREAD(child_slot, thread_slot);
+ ap_update_child_status(child_slot, thread_slot, SERVER_READY, NULL);
+
+ while (rc = DosReadQueue(workq, &rd, &len, (PPVOID)&worker_args, 0, DCWW_WAIT, &priority, NULLHANDLE),
+ rc == 0 && rd.ulData != WORKTYPE_EXIT) {
+ pconn = worker_args->pconn;
+ ap_sock_disable_nagle(worker_args->conn_sd);
+ current_conn = ap_new_connection(pconn, ap_server_conf, worker_args->conn_sd, conn_id);
+
+ if (current_conn) {
+ ap_process_connection(current_conn);
+ ap_lingering_close(current_conn);
+ }
+
+ apr_pool_destroy(pconn);
+ ap_update_child_status(child_slot, thread_slot, SERVER_READY, NULL);
+ }
+
+ ap_update_child_status(child_slot, thread_slot, SERVER_DEAD, NULL);
+}
+
+
+
+static void server_maintenance(void *vpArg)
+{
+ int num_idle, num_needed;
+ ULONG num_pending = 0;
+ int threadnum;
+ HQUEUE workq;
+ ULONG rc;
+ PID owner;
+
+ rc = DosOpenQueue(&owner, &workq,
+ apr_psprintf(pchild, "/queues/httpd/work.%d", getpid()));
+
+ if (rc) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
+ "unable to open work queue in maintenance thread");
+ return;
+ }
+
+ do {
+ for (num_idle=0, threadnum=0; threadnum < HARD_THREAD_LIMIT; threadnum++) {
+ num_idle += ap_scoreboard_image->servers[child_slot][threadnum].status == SERVER_READY;
+ }
+
+ DosQueryQueue(workq, &num_pending);
+ num_needed = ap_min_spare_threads - num_idle + num_pending;
+
+ if (num_needed > 0) {
+ for (threadnum=0; threadnum < num_needed; threadnum++) {
+ add_worker();
+ }
+ }
+
+ if (num_idle - num_pending > ap_max_spare_threads) {
+ DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0);
+ }
+ } while (DosWaitEventSem(shutdown_event, 500) == ERROR_TIMEOUT);
+}
+
+
+
+/* Signal handling routines */
+
+static void sig_term(int sig)
+{
+ shutdown_pending = 1;
+ is_graceful = 0;
+ signal(SIGTERM, SIG_DFL);
+}
+
+
+
+static void sig_hup(int sig)
+{
+ shutdown_pending = 1;
+ is_graceful = 1;
+}
+
+
+
+static void set_signals()
+{
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = sig_term;
+
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
+
+ sa.sa_handler = sig_hup;
+
+ if (sigaction(SIGHUP, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
+}
diff --git a/server/mpm/worker/.cvsignore b/server/mpm/worker/.cvsignore
new file mode 100644
index 00000000000..84df2572148
--- /dev/null
+++ b/server/mpm/worker/.cvsignore
@@ -0,0 +1,5 @@
+.deps
+.libs
+*.lo
+*.la
+Makefile
diff --git a/server/mpm/worker/Makefile.in b/server/mpm/worker/Makefile.in
new file mode 100644
index 00000000000..64a02436f3c
--- /dev/null
+++ b/server/mpm/worker/Makefile.in
@@ -0,0 +1,5 @@
+
+LTLIBRARY_NAME = libworker.la
+LTLIBRARY_SOURCES = worker.c fdqueue.c
+
+include $(top_srcdir)/build/ltlib.mk
diff --git a/server/mpm/worker/config5.m4 b/server/mpm/worker/config5.m4
new file mode 100644
index 00000000000..52ab50e82ce
--- /dev/null
+++ b/server/mpm/worker/config5.m4
@@ -0,0 +1,5 @@
+dnl ## XXX - Need a more thorough check of the proper flags to use
+
+if test "$MPM_NAME" = "worker" ; then
+ APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
+fi
diff --git a/server/mpm/worker/fdqueue.c b/server/mpm/worker/fdqueue.c
new file mode 100644
index 00000000000..147a3b7a946
--- /dev/null
+++ b/server/mpm/worker/fdqueue.c
@@ -0,0 +1,161 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#include "fdqueue.h"
+#include "apr_pools.h"
+
+/* Assumption: queue itself is allocated by the user */
+/* Assumption: increment and decrement are atomic on int */
+
+int ap_queue_size(FDQueue *queue) {
+ return ((queue->tail - queue->head + queue->bounds) % queue->bounds);
+}
+
+int ap_queue_full(FDQueue *queue) {
+ return(queue->blanks <= 0);
+}
+
+int ap_block_on_queue(FDQueue *queue) {
+#if 0
+ if (pthread_mutex_lock(&queue->one_big_mutex) != 0) {
+ return FD_QUEUE_FAILURE;
+ }
+#endif
+ if (ap_queue_full(queue)) {
+ pthread_cond_wait(&queue->not_full, &queue->one_big_mutex);
+ }
+#if 0
+ if (pthread_mutex_unlock(&queue->one_big_mutex) != 0) {
+ return FD_QUEUE_FAILURE;
+ }
+#endif
+ return FD_QUEUE_SUCCESS;
+}
+
+static int increase_blanks(FDQueue *queue) {
+ queue->blanks++;
+ return FD_QUEUE_SUCCESS;
+}
+
+static apr_status_t ap_queue_destroy(void *data) {
+ FDQueue *queue = data;
+ /* Ignore errors here, we can't do anything about them anyway */
+ pthread_cond_destroy(&queue->not_empty);
+ pthread_cond_destroy(&queue->not_full);
+ pthread_mutex_destroy(&queue->one_big_mutex);
+ return FD_QUEUE_SUCCESS;
+}
+
+int ap_queue_init(FDQueue *queue, int queue_capacity, apr_pool_t *a) {
+ int i;
+ int bounds = queue_capacity + 1;
+ pthread_mutex_init(&queue->one_big_mutex, NULL);
+ pthread_cond_init(&queue->not_empty, NULL);
+ pthread_cond_init(&queue->not_full, NULL);
+ queue->head = queue->tail = 0;
+ queue->data = apr_palloc(a, bounds * sizeof(FDQueueElement));
+ queue->bounds = bounds;
+ queue->blanks = queue_capacity;
+ apr_pool_cleanup_register(a, queue, ap_queue_destroy, apr_pool_cleanup_null);
+ for (i=0; i < bounds; ++i)
+ queue->data[i].sd = NULL;
+ return FD_QUEUE_SUCCESS;
+}
+
+int ap_queue_push(FDQueue *queue, apr_socket_t *sd, apr_pool_t *p) {
+ queue->data[queue->tail].sd = sd;
+ queue->data[queue->tail].p = p;
+ queue->tail = (queue->tail + 1) % queue->bounds;
+ queue->blanks--;
+ pthread_cond_signal(&queue->not_empty);
+#if 0
+ if (queue->head == (queue->tail + 1) % queue->bounds) {
+#endif
+ if (ap_queue_full(queue)) {
+ pthread_cond_wait(&queue->not_full, &queue->one_big_mutex);
+ }
+ return FD_QUEUE_SUCCESS;
+}
+
+apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p, int block_if_empty) {
+ increase_blanks(queue);
+ /* We have just removed one from the queue. By definition, it is
+ * no longer full. We can ALWAYS signal the listener thread at
+ * this point. However, the original code didn't do it this way,
+ * so I am leaving the original code in, just commented out. BTW,
+ * originally, the increase_blanks wasn't in this function either.
+ *
+ if (queue->blanks > 0) {
+ */
+ pthread_cond_signal(&queue->not_full);
+
+ /* } */
+ if (queue->head == queue->tail) {
+ if (block_if_empty) {
+ pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
+ }
+ }
+
+ *sd = queue->data[queue->head].sd;
+ *p = queue->data[queue->head].p;
+ queue->data[queue->head].sd = NULL;
+ if (*sd != NULL) {
+ queue->head = (queue->head + 1) % queue->bounds;
+ }
+ return APR_SUCCESS;
+}
diff --git a/server/mpm/worker/fdqueue.h b/server/mpm/worker/fdqueue.h
new file mode 100644
index 00000000000..b1cab2d0186
--- /dev/null
+++ b/server/mpm/worker/fdqueue.h
@@ -0,0 +1,95 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef FDQUEUE_H
+#define FDQUEUE_H
+#include "httpd.h"
+#include
+#include
+#include
+#include
+#include
+
+#define FD_QUEUE_SUCCESS 0
+#define FD_QUEUE_FAILURE -1 /* Needs to be an invalid file descriptor because
+ of queue_pop semantics */
+
+typedef struct fd_queue_elem {
+ apr_socket_t *sd;
+ apr_pool_t *p;
+} FDQueueElement;
+
+typedef struct fd_queue {
+ int head;
+ int tail;
+ FDQueueElement *data;
+ int bounds;
+ int blanks;
+ pthread_mutex_t one_big_mutex;
+ pthread_cond_t not_empty;
+ pthread_cond_t not_full;
+} FDQueue;
+
+int ap_queue_init(FDQueue *queue, int queue_size, apr_pool_t *a);
+int ap_queue_push(FDQueue *queue, apr_socket_t *sd, apr_pool_t *p);
+apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p, int block_if_empty);
+int ap_queue_size(FDQueue *queue);
+int ap_queue_full(FDQueue *queue);
+int ap_block_on_queue(FDQueue *queue);
+
+#endif /* FDQUEUE_H */
diff --git a/server/mpm/worker/mpm.h b/server/mpm/worker/mpm.h
new file mode 100644
index 00000000000..23ed27c1ea0
--- /dev/null
+++ b/server/mpm/worker/mpm.h
@@ -0,0 +1,78 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+#include "scoreboard.h"
+#include "unixd.h"
+
+#ifndef APACHE_MPM_WORKER_H
+#define APACHE_MPM_WORKER_H
+
+#define WORKER_MPM
+
+#define MPM_NAME "Worker"
+
+#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1
+#define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image())
+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
+
+extern int ap_threads_per_child;
+extern int ap_max_daemons_limit;
+extern server_rec *ap_server_conf;
+extern char ap_coredump_dir[MAX_STRING_LEN];
+
+#endif /* APACHE_MPM_WORKER_H */
diff --git a/server/mpm/worker/mpm_default.h b/server/mpm/worker/mpm_default.h
new file mode 100644
index 00000000000..84c1304bfa8
--- /dev/null
+++ b/server/mpm/worker/mpm_default.h
@@ -0,0 +1,154 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef APACHE_MPM_DEFAULT_H
+#define APACHE_MPM_DEFAULT_H
+
+#define AP_ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t)
+#define AP_CHILD_THREAD_FROM_ID(i) (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT)
+
+/* Number of servers to spawn off by default --- also, if fewer than
+ * this free when the caretaker checks, it will spawn more.
+ */
+#ifndef DEFAULT_START_DAEMON
+#define DEFAULT_START_DAEMON 3
+#endif
+
+/* Maximum number of *free* server processes --- more than this, and
+ * they will die off.
+ */
+
+#ifndef DEFAULT_MAX_FREE_DAEMON
+#define DEFAULT_MAX_FREE_DAEMON 10
+#endif
+
+/* Minimum --- fewer than this, and more will be created */
+
+#ifndef DEFAULT_MIN_FREE_DAEMON
+#define DEFAULT_MIN_FREE_DAEMON 3
+#endif
+
+/* Limit on the total --- clients will be locked out if more servers than
+ * this are needed. It is intended solely to keep the server from crashing
+ * when things get out of hand.
+ *
+ * We keep a hard maximum number of servers, for two reasons --- first off,
+ * in case something goes seriously wrong, we want to stop the fork bomb
+ * short of actually crashing the machine we're running on by filling some
+ * kernel table. Secondly, it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifdef NO_THREADS
+#define HARD_SERVER_LIMIT 256
+#endif
+#ifndef HARD_SERVER_LIMIT
+#define HARD_SERVER_LIMIT 8
+#endif
+
+/* Limit on the threads per process. Clients will be locked out if more than
+ * this * HARD_SERVER_LIMIT are needed.
+ *
+ * We keep this for one reason it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifdef NO_THREADS
+#define HARD_THREAD_LIMIT 1
+#endif
+#ifndef HARD_THREAD_LIMIT
+#define HARD_THREAD_LIMIT 64
+#endif
+
+#ifdef NO_THREADS
+#define DEFAULT_THREADS_PER_CHILD 1
+#endif
+#ifndef DEFAULT_THREADS_PER_CHILD
+#define DEFAULT_THREADS_PER_CHILD 25
+#endif
+
+/* File used for accept locking, when we use a file */
+#ifndef DEFAULT_LOCKFILE
+#define DEFAULT_LOCKFILE "logs/accept.lock"
+#endif
+
+/* Scoreboard file, if there is one */
+#ifndef DEFAULT_SCOREBOARD
+#define DEFAULT_SCOREBOARD "logs/apache_runtime_status"
+#endif
+
+/* Where the main/parent process's pid is logged */
+#ifndef DEFAULT_PIDLOG
+#define DEFAULT_PIDLOG "logs/httpd.pid"
+#endif
+
+/*
+ * Interval, in microseconds, between scoreboard maintenance.
+ */
+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
+#endif
+
+/* Number of requests to try to handle in a single process. If <= 0,
+ * the children don't die off.
+ */
+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
+#endif
+
+#endif /* AP_MPM_DEFAULT_H */
diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c
new file mode 100644
index 00000000000..9f969af51c4
--- /dev/null
+++ b/server/mpm/worker/worker.c
@@ -0,0 +1,1660 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#include "apr.h"
+#include "apr_portable.h"
+#include "apr_strings.h"
+#include "apr_file_io.h"
+#include "apr_thread_proc.h"
+#include "apr_signal.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#if APR_HAVE_UNISTD_H
+#include
+#endif
+#if APR_HAVE_SYS_SOCKET_H
+#include
+#endif
+#if APR_HAVE_SYS_WAIT_H
+#include
+#endif
+#ifdef HAVE_SYS_PROCESSOR_H
+#include /* for bindprocessor() */
+#endif
+
+#if !APR_HAS_THREADS
+#error The Worker MPM requires APR threads, but they are unavailable.
+#endif
+
+#define CORE_PRIVATE
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h" /* for read_config */
+#include "http_core.h" /* for get_remote_host */
+#include "http_connection.h"
+#include "ap_mpm.h"
+#include "unixd.h"
+#include "mpm_common.h"
+#include "ap_listen.h"
+#include "scoreboard.h"
+#include "fdqueue.h"
+
+#include
+#include /* for INT_MAX */
+
+/*
+ * Actual definitions of config globals
+ */
+
+int ap_threads_per_child=0; /* Worker threads per child */
+static int ap_max_requests_per_child=0;
+static const char *ap_pid_fname=NULL;
+static int ap_daemons_to_start=0;
+static int min_spare_threads=0;
+static int max_spare_threads=0;
+static int ap_daemons_limit=0;
+static int dying = 0;
+static int workers_may_exit = 0;
+static int requests_this_child;
+static int num_listensocks = 0;
+static apr_socket_t **listensocks;
+static FDQueue *worker_queue;
+
+/* The structure used to pass unique initialization info to each thread */
+typedef struct {
+ int pid;
+ int tid;
+ int sd;
+ apr_pool_t *tpool; /* "pthread" would be confusing */
+} proc_info;
+
+/* Structure used to pass information to the thread responsible for
+ * creating the rest of the threads.
+ */
+typedef struct {
+ apr_thread_t **threads;
+ int child_num_arg;
+ apr_threadattr_t *threadattr;
+} thread_starter;
+
+/*
+ * The max child slot ever assigned, preserved across restarts. Necessary
+ * to deal with MaxClients changes across SIGWINCH restarts. We use this
+ * value to optimize routines that have to scan the entire scoreboard.
+ */
+int ap_max_daemons_limit = -1;
+
+char ap_coredump_dir[MAX_STRING_LEN];
+
+static apr_file_t *pipe_of_death_in = NULL;
+static apr_file_t *pipe_of_death_out = NULL;
+static apr_lock_t *pipe_of_death_mutex; /* insures that a child process only
+ consumes one character */
+
+/* *Non*-shared http_main globals... */
+
+server_rec *ap_server_conf;
+
+/* one_process --- debugging mode variable; can be set from the command line
+ * with the -X flag. If set, this gets you the child_main loop running
+ * in the process which originally started up (no detach, no make_child),
+ * which is a pretty nice debugging environment. (You'll get a SIGHUP
+ * early in standalone_main; just continue through. This is the server
+ * trying to kill off any child processes which it might have lying
+ * around --- Apache doesn't keep track of their pids, it just sends
+ * SIGHUP to the process group, ignoring it in the root process.
+ * Continue through and you'll be fine.).
+ */
+
+static int one_process = 0;
+
+#ifdef DEBUG_SIGSTOP
+int raise_sigstop_flags;
+#endif
+
+static apr_pool_t *pconf; /* Pool for config stuff */
+static apr_pool_t *pchild; /* Pool for httpd child stuff */
+
+static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
+ thread. Use this instead */
+/* Keep track of the number of worker threads currently active */
+static int worker_thread_count;
+static apr_lock_t *worker_thread_count_mutex;
+
+/* Locks for accept serialization */
+static apr_lock_t *accept_mutex;
+static apr_lockmech_e_np accept_lock_mech = APR_LOCK_DEFAULT;
+static const char *lock_fname;
+
+#ifdef NO_SERIALIZED_ACCEPT
+#define SAFE_ACCEPT(stmt) APR_SUCCESS
+#else
+#define SAFE_ACCEPT(stmt) (stmt)
+#endif
+
+AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
+{
+ switch(query_code){
+ case AP_MPMQ_MAX_DAEMON_USED:
+ *result = ap_max_daemons_limit;
+ return APR_SUCCESS;
+ case AP_MPMQ_IS_THREADED:
+ *result = AP_MPMQ_STATIC;
+ return APR_SUCCESS;
+ case AP_MPMQ_IS_FORKED:
+ *result = AP_MPMQ_DYNAMIC;
+ return APR_SUCCESS;
+ case AP_MPMQ_HARD_LIMIT_DAEMONS:
+ *result = HARD_SERVER_LIMIT;
+ return APR_SUCCESS;
+ case AP_MPMQ_HARD_LIMIT_THREADS:
+ *result = HARD_THREAD_LIMIT;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_THREADS:
+ *result = ap_threads_per_child;
+ return APR_SUCCESS;
+ case AP_MPMQ_MIN_SPARE_DEAMONS:
+ *result = 0;
+ return APR_SUCCESS;
+ case AP_MPMQ_MIN_SPARE_THREADS:
+ *result = min_spare_threads;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_SPARE_DAEMONS:
+ *result = 0;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_SPARE_THREADS:
+ *result = max_spare_threads;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_REQUESTS_DEAMON:
+ *result = ap_max_requests_per_child;
+ return APR_SUCCESS;
+ case AP_MPMQ_MAX_DAEMONS:
+ *result = ap_daemons_limit;
+ return APR_SUCCESS;
+ }
+ return APR_ENOTIMPL;
+}
+
+/* a clean exit from a child with proper cleanup */
+static void clean_child_exit(int code) __attribute__ ((noreturn));
+static void clean_child_exit(int code)
+{
+ if (pchild) {
+ apr_pool_destroy(pchild);
+ }
+ exit(code);
+}
+
+/* handle all varieties of core dumping signals */
+static void sig_coredump(int sig)
+{
+ chdir(ap_coredump_dir);
+ apr_signal(sig, SIG_DFL);
+ kill(ap_my_pid, sig);
+ /* At this point we've got sig blocked, because we're still inside
+ * the signal handler. When we leave the signal handler it will
+ * be unblocked, and we'll take the signal... and coredump or whatever
+ * is appropriate for this particular Unix. In addition the parent
+ * will see the real signal we received -- whereas if we called
+ * abort() here, the parent would only see SIGABRT.
+ */
+}
+
+static void just_die(int sig)
+{
+ clean_child_exit(0);
+}
+
+/*****************************************************************
+ * Connection structures and accounting...
+ */
+
+/* volatile just in case */
+static int volatile shutdown_pending;
+static int volatile restart_pending;
+static int volatile is_graceful;
+ap_generation_t volatile ap_my_generation;
+
+/*
+ * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
+ * functions to initiate shutdown or restart without relying on signals.
+ * Previously this was initiated in sig_term() and restart() signal handlers,
+ * but we want to be able to start a shutdown/restart from other sources --
+ * e.g. on Win32, from the service manager. Now the service manager can
+ * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
+ * these functions can also be called by the child processes, since global
+ * variables are no longer used to pass on the required action to the parent.
+ *
+ * These should only be called from the parent process itself, since the
+ * parent process will use the shutdown_pending and restart_pending variables
+ * to determine whether to shutdown or restart. The child process should
+ * call signal_parent() directly to tell the parent to die -- this will
+ * cause neither of those variable to be set, which the parent will
+ * assume means something serious is wrong (which it will be, for the
+ * child to force an exit) and so do an exit anyway.
+ */
+
+static void ap_start_shutdown(void)
+{
+ if (shutdown_pending == 1) {
+ /* Um, is this _probably_ not an error, if the user has
+ * tried to do a shutdown twice quickly, so we won't
+ * worry about reporting it.
+ */
+ return;
+ }
+ shutdown_pending = 1;
+}
+
+/* do a graceful restart if graceful == 1 */
+static void ap_start_restart(int graceful)
+{
+
+ if (restart_pending == 1) {
+ /* Probably not an error - don't bother reporting it */
+ return;
+ }
+ restart_pending = 1;
+ is_graceful = graceful;
+ if (is_graceful) {
+ apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard);
+ }
+}
+
+static void sig_term(int sig)
+{
+ ap_start_shutdown();
+}
+
+static void restart(int sig)
+{
+ ap_start_restart(sig == SIGWINCH);
+}
+
+static void set_signals(void)
+{
+#ifndef NO_USE_SIGACTION
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (!one_process) {
+ sa.sa_handler = sig_coredump;
+#if defined(SA_ONESHOT)
+ sa.sa_flags = SA_ONESHOT;
+#elif defined(SA_RESETHAND)
+ sa.sa_flags = SA_RESETHAND;
+#endif
+ if (sigaction(SIGSEGV, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
+#ifdef SIGBUS
+ if (sigaction(SIGBUS, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
+#endif
+#ifdef SIGABORT
+ if (sigaction(SIGABORT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
+#endif
+#ifdef SIGABRT
+ if (sigaction(SIGABRT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
+#endif
+#ifdef SIGILL
+ if (sigaction(SIGILL, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
+#endif
+ sa.sa_flags = 0;
+ }
+ sa.sa_handler = sig_term;
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
+#ifdef SIGINT
+ if (sigaction(SIGINT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
+#endif
+#ifdef SIGXCPU
+ sa.sa_handler = SIG_DFL;
+ if (sigaction(SIGXCPU, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");
+#endif
+#ifdef SIGXFSZ
+ sa.sa_handler = SIG_DFL;
+ if (sigaction(SIGXFSZ, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");
+#endif
+#ifdef SIGPIPE
+ sa.sa_handler = SIG_IGN;
+ if (sigaction(SIGPIPE, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
+#endif
+
+ /* we want to ignore HUPs and WINCH while we're busy processing one */
+ sigaddset(&sa.sa_mask, SIGHUP);
+ sigaddset(&sa.sa_mask, SIGWINCH);
+ sa.sa_handler = restart;
+ if (sigaction(SIGHUP, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
+ if (sigaction(SIGWINCH, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)");
+#else
+ if (!one_process) {
+ apr_signal(SIGSEGV, sig_coredump);
+#ifdef SIGBUS
+ apr_signal(SIGBUS, sig_coredump);
+#endif /* SIGBUS */
+#ifdef SIGABORT
+ apr_signal(SIGABORT, sig_coredump);
+#endif /* SIGABORT */
+#ifdef SIGABRT
+ apr_signal(SIGABRT, sig_coredump);
+#endif /* SIGABRT */
+#ifdef SIGILL
+ apr_signal(SIGILL, sig_coredump);
+#endif /* SIGILL */
+#ifdef SIGXCPU
+ apr_signal(SIGXCPU, SIG_DFL);
+#endif /* SIGXCPU */
+#ifdef SIGXFSZ
+ apr_signal(SIGXFSZ, SIG_DFL);
+#endif /* SIGXFSZ */
+ }
+
+ apr_signal(SIGTERM, sig_term);
+#ifdef SIGHUP
+ apr_signal(SIGHUP, restart);
+#endif /* SIGHUP */
+#ifdef SIGWINCH
+ apr_signal(SIGWINCH, restart);
+#endif /* SIGWINCH */
+#ifdef SIGPIPE
+ apr_signal(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+
+#endif
+}
+
+/*****************************************************************
+ * Here follows a long bunch of generic server bookkeeping stuff...
+ */
+
+int ap_graceful_stop_signalled(void)
+{
+ /* XXX - Does this really work? - Manoj */
+ return is_graceful;
+}
+
+/*****************************************************************
+ * Child process main loop.
+ */
+
+static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, int my_thread_num)
+{
+ conn_rec *current_conn;
+ long conn_id = AP_ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
+ int csd;
+
+ (void) apr_os_sock_get(&csd, sock);
+
+ if (csd >= FD_SETSIZE) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL,
+ "new file descriptor %d is too large; you probably need "
+ "to rebuild Apache with a larger FD_SETSIZE "
+ "(currently %d)",
+ csd, FD_SETSIZE);
+ apr_socket_close(sock);
+ return;
+ }
+
+ ap_sock_disable_nagle(sock);
+
+ current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ if (current_conn) {
+ ap_process_connection(current_conn);
+ ap_lingering_close(current_conn);
+ }
+}
+
+/* requests_this_child has gone to zero or below. See if the admin coded
+ "MaxRequestsPerChild 0", and keep going in that case. Doing it this way
+ simplifies the hot path in worker_thread */
+
+static void check_infinite_requests(void)
+{
+ if (ap_max_requests_per_child) {
+ workers_may_exit = 1;
+ }
+ else {
+ /* wow! if you're executing this code, you may have set a record.
+ * either this child process has served over 2 billion requests, or
+ * you're running a threaded 2.0 on a 16 bit machine.
+ *
+ * I'll buy pizza and beers at Apachecon for the first person to do
+ * the former without cheating (dorking with INT_MAX, or running with
+ * uncommitted performance patches, for example).
+ *
+ * for the latter case, you probably deserve a beer too. Greg Ames
+ */
+
+ requests_this_child = INT_MAX; /* keep going */
+ }
+}
+
+/* Sets workers_may_exit if we received a character on the pipe_of_death */
+static void check_pipe_of_death(void)
+{
+ apr_lock_acquire(pipe_of_death_mutex);
+ if (!workers_may_exit) {
+ apr_status_t ret;
+ char pipe_read_char;
+ apr_size_t n = 1;
+
+ ret = apr_recv(listensocks[0], &pipe_read_char, &n);
+ if (APR_STATUS_IS_EAGAIN(ret)) {
+ /* It lost the lottery. It must continue to suffer
+ * through a life of servitude. */
+ }
+ else {
+ /* It won the lottery (or something else is very
+ * wrong). Embrace death with open arms. */
+ workers_may_exit = 1;
+ }
+ }
+ apr_lock_release(pipe_of_death_mutex);
+}
+
+static void *listener_thread(apr_thread_t *thd, void * dummy)
+{
+ proc_info * ti = dummy;
+ int process_slot = ti->pid;
+ int thread_slot = ti->tid;
+ apr_pool_t *tpool = ti->tpool;
+ apr_socket_t *csd = NULL;
+ apr_pool_t *ptrans; /* Pool for per-transaction stuff */
+ apr_socket_t *sd = NULL;
+ int n;
+ int curr_pollfd, last_pollfd = 0;
+ apr_pollfd_t *pollset;
+ apr_status_t rv;
+
+ free(ti);
+
+ apr_pool_create(&ptrans, tpool);
+
+ apr_lock_acquire(worker_thread_count_mutex);
+ worker_thread_count++;
+ apr_lock_release(worker_thread_count_mutex);
+
+ apr_poll_setup(&pollset, num_listensocks+1, tpool);
+ for(n=0 ; n <= num_listensocks ; ++n)
+ apr_poll_socket_add(pollset, listensocks[n], APR_POLLIN);
+
+ worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
+ ap_queue_init(worker_queue, ap_threads_per_child, pchild);
+
+ /* TODO: Switch to a system where threads reuse the results from earlier
+ poll calls - manoj */
+ while (1) {
+ if (requests_this_child <= 0) {
+ check_infinite_requests();
+ }
+ if (workers_may_exit) break;
+
+ if ((rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
+ != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "apr_lock_acquire failed. Attempting to shutdown "
+ "process gracefully.");
+ workers_may_exit = 1;
+ }
+
+ while (!workers_may_exit) {
+ apr_status_t ret;
+ apr_int16_t event;
+
+ ret = apr_poll(pollset, &n, -1);
+ if (ret != APR_SUCCESS) {
+ if (APR_STATUS_IS_EINTR(ret)) {
+ continue;
+ }
+
+ /* apr_poll() will only return errors in catastrophic
+ * circumstances. Let's try exiting gracefully, for now. */
+ ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *)
+ ap_server_conf, "apr_poll: (listen)");
+ workers_may_exit = 1;
+ }
+
+ if (workers_may_exit) break;
+
+ apr_poll_revents_get(&event, listensocks[0], pollset);
+ if (event & APR_POLLIN) {
+ /* A process got a signal on the shutdown pipe. Check if we're
+ * the lucky process to die. */
+ check_pipe_of_death();
+ continue;
+ }
+
+ if (num_listensocks == 1) {
+ sd = ap_listeners->sd;
+ goto got_fd;
+ }
+ else {
+ /* find a listener */
+ curr_pollfd = last_pollfd;
+ do {
+ curr_pollfd++;
+ if (curr_pollfd > num_listensocks) {
+ curr_pollfd = 1;
+ }
+ /* XXX: Should we check for POLLERR? */
+ apr_poll_revents_get(&event, listensocks[curr_pollfd], pollset);
+ if (event & APR_POLLIN) {
+ last_pollfd = curr_pollfd;
+ sd=listensocks[curr_pollfd];
+ goto got_fd;
+ }
+ } while (curr_pollfd != last_pollfd);
+ }
+ }
+ got_fd:
+ if (!workers_may_exit) {
+ if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) {
+ csd = NULL;
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
+ "apr_accept");
+ }
+ if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex)))
+ != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "apr_lock_release failed. Attempting to shutdown "
+ "process gracefully.");
+ workers_may_exit = 1;
+ }
+ if (csd != NULL) {
+ ap_queue_push(worker_queue, csd, ptrans);
+ ap_block_on_queue(worker_queue);
+ }
+ }
+ else {
+ if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex)))
+ != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "apr_lock_release failed. Attempting to shutdown "
+ "process gracefully.");
+ workers_may_exit = 1;
+ }
+ break;
+ }
+ }
+
+ apr_pool_destroy(tpool);
+ ap_update_child_status(process_slot, thread_slot, (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
+ (request_rec *) NULL);
+ dying = 1;
+ apr_lock_acquire(worker_thread_count_mutex);
+ worker_thread_count--;
+ if (worker_thread_count == 0) {
+ /* All the threads have exited, now finish the shutdown process
+ * by signalling the sigwait thread */
+ kill(ap_my_pid, SIGTERM);
+ }
+ apr_lock_release(worker_thread_count_mutex);
+
+ return NULL;
+}
+
+static void *worker_thread(apr_thread_t *thd, void * dummy)
+{
+ proc_info * ti = dummy;
+ int process_slot = ti->pid;
+ int thread_slot = ti->tid;
+ apr_pool_t *tpool = ti->tpool;
+ apr_socket_t *csd = NULL;
+ apr_pool_t *ptrans; /* Pool for per-transaction stuff */
+ apr_socket_t *sd = NULL;
+ int n;
+ int curr_pollfd, last_pollfd = 0;
+ apr_pollfd_t *pollset;
+ apr_status_t rv;
+
+ free(ti);
+
+ while (!workers_may_exit) {
+ ap_queue_pop(worker_queue, &csd, &ptrans, 1);
+ process_socket(ptrans, csd, process_slot, thread_slot);
+ requests_this_child--;
+ apr_pool_clear(ptrans);
+ }
+
+ apr_pool_destroy(tpool);
+ ap_update_child_status(process_slot, thread_slot, (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
+ (request_rec *) NULL);
+ apr_lock_acquire(worker_thread_count_mutex);
+ if (!dying) {
+ /* this is the first thread to exit */
+ if (ap_my_pid == ap_scoreboard_image->parent[process_slot].pid) {
+ /* tell the parent that it may use this scoreboard slot */
+ ap_scoreboard_image->parent[process_slot].quiescing = 1;
+ }
+ dying = 1;
+ }
+ worker_thread_count--;
+ if (worker_thread_count == 0) {
+ /* All the threads have exited, now finish the shutdown process
+ * by signalling the sigwait thread */
+ kill(ap_my_pid, SIGTERM);
+ }
+ apr_lock_release(worker_thread_count_mutex);
+
+ return NULL;
+}
+
+static int check_signal(int signum)
+{
+ switch (signum) {
+ case SIGTERM:
+ case SIGINT:
+ return 1;
+ }
+ return 0;
+}
+
+static void *start_threads(apr_thread_t *thd, void * dummy)
+{
+ thread_starter *ts = dummy;
+ apr_thread_t **threads = ts->threads;
+ apr_threadattr_t *thread_attr = ts->threadattr;
+ int child_num_arg = ts->child_num_arg;
+ int i;
+ int my_child_num = child_num_arg;
+ proc_info *my_info = NULL;
+ apr_status_t rv;
+ int threads_created = 0;
+ apr_thread_t *listener;
+
+ while (1) {
+ my_info = (proc_info *)malloc(sizeof(proc_info));
+ my_info->pid = my_child_num;
+ my_info->tid = i;
+ my_info->sd = 0;
+ apr_pool_create(&my_info->tpool, pchild);
+ apr_thread_create(&listener, thread_attr, listener_thread, my_info, pchild);
+ for (i=0; i < ap_threads_per_child; i++) {
+ int status = ap_scoreboard_image->servers[child_num_arg][i].status;
+
+ if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
+ continue;
+ }
+
+ my_info = (proc_info *)malloc(sizeof(proc_info));
+ if (my_info == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
+ "malloc: out of memory");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+ my_info->pid = my_child_num;
+ my_info->tid = i;
+ my_info->sd = 0;
+ apr_pool_create(&my_info->tpool, pchild);
+
+ /* We are creating threads right now */
+ (void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
+ (request_rec *) NULL);
+ /* We let each thread update its own scoreboard entry. This is
+ * done because it lets us deal with tid better.
+ */
+ if ((rv = apr_thread_create(&threads[i], thread_attr, worker_thread, my_info, pchild))) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
+ "apr_thread_create: unable to create worker thread");
+ /* In case system resources are maxxed out, we don't want
+ Apache running away with the CPU trying to fork over and
+ over and over again if we exit. */
+ sleep(10);
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+ threads_created++;
+ }
+ if (workers_may_exit || threads_created == ap_threads_per_child) {
+ break;
+ }
+ sleep(1); /* wait for previous generation to clean up an entry */
+ }
+
+ /* What state should this child_main process be listed as in the scoreboard...?
+ * ap_update_child_status(my_child_num, i, SERVER_STARTING, (request_rec *) NULL);
+ *
+ * This state should be listed separately in the scoreboard, in some kind
+ * of process_status, not mixed in with the worker threads' status.
+ * "life_status" is almost right, but it's in the worker's structure, and
+ * the name could be clearer. gla
+ */
+ return NULL;
+}
+
+static void child_main(int child_num_arg)
+{
+ apr_thread_t **threads;
+ int i;
+ ap_listen_rec *lr;
+ apr_status_t rv;
+ thread_starter *ts;
+ apr_threadattr_t *thread_attr;
+ apr_thread_t *start_thread_id;
+
+ ap_my_pid = getpid();
+ apr_pool_create(&pchild, pconf);
+
+ /*stuff to do before we switch id's, so we have permissions.*/
+ reopen_scoreboard(pchild);
+
+ rv = SAFE_ACCEPT(apr_lock_child_init(&accept_mutex, lock_fname,
+ pchild));
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "Couldn't initialize cross-process lock in child");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ if (unixd_setup_child()) {
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ ap_run_child_init(pchild, ap_server_conf);
+
+ /*done with init critical section */
+
+ rv = apr_setup_signal_thread();
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "Couldn't initialize signal thread");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ if (ap_max_requests_per_child) {
+ requests_this_child = ap_max_requests_per_child;
+ }
+ else {
+ /* coding a value of zero means infinity */
+ requests_this_child = INT_MAX;
+ }
+
+ /* Set up the pollfd array */
+ listensocks = apr_pcalloc(pchild,
+ sizeof(*listensocks) * (num_listensocks + 1));
+#if APR_FILES_AS_SOCKETS
+ apr_socket_from_file(&listensocks[0], pipe_of_death_in);
+#endif
+ for (lr = ap_listeners, i = 1; i <= num_listensocks; lr = lr->next, ++i)
+ listensocks[i]=lr->sd;
+
+ /* Setup worker threads */
+
+ /* clear the storage; we may not create all our threads immediately, and we want
+ * a 0 entry to indicate a thread which was not created
+ */
+ threads = (apr_thread_t **)calloc(1, sizeof(apr_thread_t *) * ap_threads_per_child);
+ if (threads == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
+ "malloc: out of memory");
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+ worker_thread_count = 0;
+ apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS,
+ NULL, pchild);
+ apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS,
+ NULL, pchild);
+
+ ts = apr_palloc(pchild, sizeof(*ts));
+
+ apr_threadattr_create(&thread_attr, pchild);
+ apr_threadattr_detach_set(thread_attr, 0); /* 0 means PTHREAD_CREATE_JOINABLE */
+
+ ts->threads = threads;
+ ts->child_num_arg = child_num_arg;
+ ts->threadattr = thread_attr;
+
+ if ((rv = apr_thread_create(&start_thread_id, thread_attr, start_threads, ts, pchild))) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
+ "apr_thread_create: unable to create worker thread");
+ /* In case system resources are maxxed out, we don't want
+ Apache running away with the CPU trying to fork over and
+ over and over again if we exit. */
+ sleep(10);
+ clean_child_exit(APEXIT_CHILDFATAL);
+ }
+
+ apr_signal_thread(check_signal);
+
+ workers_may_exit = 1; /* helps us terminate a little more quickly when
+ * the dispatch of the signal thread
+ * beats the Pipe of Death and the browsers
+ */
+
+ /* A terminating signal was received. Now join each of the workers to clean them up.
+ * If the worker already exited, then the join frees their resources and returns.
+ * If the worker hasn't exited, then this blocks until they have (then cleans up).
+ */
+ apr_thread_join(&rv, start_thread_id);
+ for (i = 0; i < ap_threads_per_child; i++) {
+ if (threads[i]) { /* if we ever created this thread */
+ apr_thread_join(&rv, threads[i]);
+ }
+ }
+
+ free(threads);
+
+ clean_child_exit(0);
+}
+
+static int make_child(server_rec *s, int slot)
+{
+ int pid;
+
+ if (slot + 1 > ap_max_daemons_limit) {
+ ap_max_daemons_limit = slot + 1;
+ }
+
+ if (one_process) {
+ set_signals();
+ ap_scoreboard_image->parent[slot].pid = getpid();
+ child_main(slot);
+ }
+
+ if ((pid = fork()) == -1) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process");
+
+ /* fork didn't succeed. Fix the scoreboard or else
+ * it will say SERVER_STARTING forever and ever
+ */
+ (void) ap_update_child_status(slot, 0, SERVER_DEAD, (request_rec *) NULL);
+
+ /* In case system resources are maxxed out, we don't want
+ Apache running away with the CPU trying to fork over and
+ over and over again. */
+ sleep(10);
+
+ return -1;
+ }
+
+ if (!pid) {
+#ifdef HAVE_BINDPROCESSOR
+ /* By default, AIX binds to a single processor. This bit unbinds
+ * children which will then bind to another CPU.
+ */
+ int status = bindprocessor(BINDPROCESS, (int)getpid(),
+ PROCESSOR_CLASS_ANY);
+ if (status != OK)
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, ap_server_conf,
+ "processor unbind failed %d", status);
+#endif
+ RAISE_SIGSTOP(MAKE_CHILD);
+
+ apr_signal(SIGTERM, just_die);
+ child_main(slot);
+
+ clean_child_exit(0);
+ }
+ /* else */
+ ap_scoreboard_image->parent[slot].quiescing = 0;
+ ap_scoreboard_image->parent[slot].pid = pid;
+ return 0;
+}
+
+/* If there aren't many connections coming in from the network, the child
+ * processes may need to be awakened from their network i/o waits.
+ * The pipe of death is an effective prod.
+ */
+
+static void wake_up_and_die(void)
+{
+ int i;
+ char char_of_death = '!';
+ apr_size_t one = 1;
+ apr_status_t rv;
+
+ for (i = 0; i < ap_daemons_limit;) {
+ if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one))
+ != APR_SUCCESS) {
+ if (APR_STATUS_IS_EINTR(rv)) continue;
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
+ "write pipe_of_death");
+ }
+ i++;
+ }
+}
+
+/* start up a bunch of children */
+static void startup_children(int number_to_start)
+{
+ int i;
+
+ for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
+ if (ap_scoreboard_image->parent[i].pid != 0) {
+ continue;
+ }
+ if (make_child(ap_server_conf, i) < 0) {
+ break;
+ }
+ --number_to_start;
+ }
+}
+
+
+/*
+ * idle_spawn_rate is the number of children that will be spawned on the
+ * next maintenance cycle if there aren't enough idle servers. It is
+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
+ * without the need to spawn.
+ */
+static int idle_spawn_rate = 1;
+#ifndef MAX_SPAWN_RATE
+#define MAX_SPAWN_RATE (32)
+#endif
+static int hold_off_on_exponential_spawning;
+
+static void perform_idle_server_maintenance(void)
+{
+ int i, j;
+ int idle_thread_count;
+ worker_score *ws;
+ process_score *ps;
+ int free_length;
+ int free_slots[MAX_SPAWN_RATE];
+ int last_non_dead;
+ int total_non_dead;
+ apr_size_t one = 1;
+ apr_status_t rv;
+
+ /* initialize the free_list */
+ free_length = 0;
+
+ idle_thread_count = 0;
+ last_non_dead = -1;
+ total_non_dead = 0;
+
+ ap_sync_scoreboard_image();
+ for (i = 0; i < ap_daemons_limit; ++i) {
+ /* Initialization to satisfy the compiler. It doesn't know
+ * that ap_threads_per_child is always > 0 */
+ int status = SERVER_DEAD;
+ int any_dying_threads = 0;
+ int any_dead_threads = 0;
+
+ if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
+ break;
+ ps = &ap_scoreboard_image->parent[i];
+ for (j = 0; j < ap_threads_per_child; j++) {
+ ws = &ap_scoreboard_image->servers[i][j];
+ status = ws->status;
+
+ any_dying_threads = any_dying_threads || (status == SERVER_GRACEFUL);
+ any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
+
+ /* We consider a starting server as idle because we started it
+ * at least a cycle ago, and if it still hasn't finished starting
+ * then we're just going to swamp things worse by forking more.
+ * So we hopefully won't need to fork more if we count it.
+ * This depends on the ordering of SERVER_READY and SERVER_STARTING.
+ */
+ if (status <= SERVER_READY && status != SERVER_DEAD &&
+ ps->generation == ap_my_generation &&
+ /* XXX the following shouldn't be necessary if we clean up
+ * properly after seg faults, but we're not yet GLA
+ */
+ ps->pid != 0) {
+ ++idle_thread_count;
+ }
+ }
+ /* XXX any_dead_threads may not be needed any more GLA */
+ if (any_dead_threads && free_length < idle_spawn_rate
+ && (!ps->pid /* no process in the slot */
+ || ps->quiescing)) { /* or at least one is going away */
+ free_slots[free_length] = i;
+ ++free_length;
+ }
+ if (!any_dying_threads) {
+ last_non_dead = i;
+ ++total_non_dead;
+ }
+ }
+ ap_max_daemons_limit = last_non_dead + 1;
+
+ if (idle_thread_count > max_spare_threads) {
+ char char_of_death = '!';
+ /* Kill off one child */
+ if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death");
+ }
+ idle_spawn_rate = 1;
+ }
+ else if (idle_thread_count < min_spare_threads) {
+ /* terminate the free list */
+ if (free_length == 0) {
+ /* only report this condition once */
+ static int reported = 0;
+
+ if (!reported) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf,
+ "server reached MaxClients setting, consider"
+ " raising the MaxClients setting");
+ reported = 1;
+ }
+ idle_spawn_rate = 1;
+ }
+ else {
+
+ if (idle_spawn_rate >= 8) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
+ "server seems busy, (you may need "
+ "to increase StartServers, ThreadsPerChild "
+ "or Min/MaxSpareThreads), "
+ "spawning %d children, there are around %d idle "
+ "threads, and %d total children", free_length,
+ idle_thread_count, total_non_dead);
+ }
+ for (i = 0; i < free_length; ++i) {
+ make_child(ap_server_conf, free_slots[i]);
+ }
+ /* the next time around we want to spawn twice as many if this
+ * wasn't good enough, but not if we've just done a graceful
+ */
+ if (hold_off_on_exponential_spawning) {
+ --hold_off_on_exponential_spawning;
+ }
+ else if (idle_spawn_rate < MAX_SPAWN_RATE) {
+ idle_spawn_rate *= 2;
+ }
+ }
+ }
+ else {
+ idle_spawn_rate = 1;
+ }
+}
+
+static void server_main_loop(int remaining_children_to_start)
+{
+ int child_slot;
+ apr_wait_t status;
+ apr_proc_t pid;
+ int i;
+
+ while (!restart_pending && !shutdown_pending) {
+ ap_wait_or_timeout(&status, &pid, pconf);
+
+ if (pid.pid != -1) {
+ ap_process_child_status(&pid, status);
+ /* non-fatal death... note that it's gone in the scoreboard. */
+ child_slot = find_child_by_pid(&pid);
+ if (child_slot >= 0) {
+ for (i = 0; i < ap_threads_per_child; i++)
+ ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);
+
+ ap_scoreboard_image->parent[child_slot].pid = 0;
+ ap_scoreboard_image->parent[child_slot].quiescing = 0;
+ if (remaining_children_to_start
+ && child_slot < ap_daemons_limit) {
+ /* we're still doing a 1-for-1 replacement of dead
+ * children with new children
+ */
+ make_child(ap_server_conf, child_slot);
+ --remaining_children_to_start;
+ }
+#if APR_HAS_OTHER_CHILD
+ }
+ else if (apr_proc_other_child_read(&pid, status) == 0) {
+ /* handled */
+#endif
+ }
+ else if (is_graceful) {
+ /* Great, we've probably just lost a slot in the
+ * scoreboard. Somehow we don't know about this child.
+ */
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0,
+ ap_server_conf,
+ "long lost child came home! (pid %ld)",
+ (long)pid.pid);
+ }
+ /* Don't perform idle maintenance when a child dies,
+ * only do it when there's a timeout. Remember only a
+ * finite number of children can die, and it's pretty
+ * pathological for a lot to die suddenly.
+ */
+ continue;
+ }
+ else if (remaining_children_to_start) {
+ /* we hit a 1 second timeout in which none of the previous
+ * generation of children needed to be reaped... so assume
+ * they're all done, and pick up the slack if any is left.
+ */
+ startup_children(remaining_children_to_start);
+ remaining_children_to_start = 0;
+ /* In any event we really shouldn't do the code below because
+ * few of the servers we just started are in the IDLE state
+ * yet, so we'd mistakenly create an extra server.
+ */
+ continue;
+ }
+
+ perform_idle_server_maintenance();
+ }
+}
+
+int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
+{
+ int remaining_children_to_start;
+ apr_status_t rv;
+
+ pconf = _pconf;
+ ap_server_conf = s;
+
+ rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
+ (const server_rec*) ap_server_conf,
+ "apr_file_pipe_create (pipe_of_death)");
+ exit(1);
+ }
+
+ if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
+ (const server_rec*) ap_server_conf,
+ "apr_file_pipe_timeout_set (pipe_of_death)");
+ exit(1);
+ }
+
+ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
+ /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
+ "no listening sockets available, shutting down");
+ return 1;
+ }
+ ap_log_pid(pconf, ap_pid_fname);
+
+ /* Initialize cross-process accept lock */
+ lock_fname = apr_psprintf(_pconf, "%s.%" APR_OS_PROC_T_FMT,
+ ap_server_root_relative(_pconf, lock_fname),
+ ap_my_pid);
+ rv = apr_lock_create_np(&accept_mutex, APR_MUTEX, APR_LOCKALL,
+ accept_lock_mech, lock_fname, _pconf);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
+ "Couldn't create accept lock");
+ return 1;
+ }
+
+ if (!is_graceful) {
+ ap_run_pre_mpm(pconf, SB_SHARED);
+ }
+
+ set_signals();
+ /* Don't thrash... */
+ if (max_spare_threads < min_spare_threads + ap_threads_per_child)
+ max_spare_threads = min_spare_threads + ap_threads_per_child;
+
+ /* If we're doing a graceful_restart then we're going to see a lot
+ * of children exiting immediately when we get into the main loop
+ * below (because we just sent them SIGWINCH). This happens pretty
+ * rapidly... and for each one that exits we'll start a new one until
+ * we reach at least daemons_min_free. But we may be permitted to
+ * start more than that, so we'll just keep track of how many we're
+ * supposed to start up without the 1 second penalty between each fork.
+ */
+ remaining_children_to_start = ap_daemons_to_start;
+ if (remaining_children_to_start > ap_daemons_limit) {
+ remaining_children_to_start = ap_daemons_limit;
+ }
+ if (!is_graceful) {
+ startup_children(remaining_children_to_start);
+ remaining_children_to_start = 0;
+ }
+ else {
+ /* give the system some time to recover before kicking into
+ * exponential mode */
+ hold_off_on_exponential_spawning = 10;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "%s configured -- resuming normal operations",
+ ap_get_server_version());
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
+ "Server built: %s", ap_get_server_built());
+ restart_pending = shutdown_pending = 0;
+
+ server_main_loop(remaining_children_to_start);
+
+ if (shutdown_pending) {
+ /* Time to gracefully shut down:
+ * Kill child processes, tell them to call child_exit, etc...
+ */
+ wake_up_and_die();
+
+ if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
+ }
+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
+
+ /* cleanup pid file on normal shutdown */
+ {
+ const char *pidfile = NULL;
+ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
+ if ( pidfile != NULL && unlink(pidfile) == 0)
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0,
+ ap_server_conf,
+ "removed PID file %s (pid=%ld)",
+ pidfile, (long)getpid());
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "caught SIGTERM, shutting down");
+
+ return 1;
+ }
+
+ /* we've been told to restart */
+ apr_signal(SIGHUP, SIG_IGN);
+
+ if (one_process) {
+ /* not worth thinking about */
+ return 1;
+ }
+
+ /* advance to the next generation */
+ /* XXX: we really need to make sure this new generation number isn't in
+ * use by any of the children.
+ */
+ ++ap_my_generation;
+ ap_scoreboard_image->global.running_generation = ap_my_generation;
+ update_scoreboard_global();
+
+ /* wake up the children...time to die. But we'll have more soon */
+ wake_up_and_die();
+
+ if (is_graceful) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "SIGWINCH received. Doing graceful restart");
+
+ /* This is mostly for debugging... so that we know what is still
+ * gracefully dealing with existing request.
+ */
+
+ }
+ else {
+ /* Kill 'em all. Since the child acts the same on the parents SIGTERM
+ * and a SIGHUP, we may as well use the same signal, because some user
+ * pthreads are stealing signals from us left and right.
+ */
+ if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
+ }
+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
+ "SIGHUP received. Attempting to restart");
+ }
+ return 0;
+}
+
+static void worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ static int restart_num = 0;
+ int no_detach = 0;
+
+ one_process = !!ap_exists_config_define("ONE_PROCESS");
+ no_detach = !!ap_exists_config_define("NO_DETACH");
+
+ /* sigh, want this only the second time around */
+ if (restart_num++ == 1) {
+ is_graceful = 0;
+
+ if (!one_process && !no_detach) {
+ apr_proc_detach();
+ }
+ ap_my_pid = getpid();
+ }
+
+ unixd_pre_config(ptemp);
+ ap_listen_pre_config();
+ ap_daemons_to_start = DEFAULT_START_DAEMON;
+ min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
+ max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
+ ap_daemons_limit = HARD_SERVER_LIMIT;
+ ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
+ ap_pid_fname = DEFAULT_PIDLOG;
+ ap_scoreboard_fname = DEFAULT_SCOREBOARD;
+ lock_fname = DEFAULT_LOCKFILE;
+ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
+ ap_extended_status = 0;
+
+ apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
+}
+
+static void worker_hooks(apr_pool_t *p)
+{
+ one_process = 0;
+
+ ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+
+static const char *set_pidfile(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (cmd->server->is_virtual) {
+ return "PidFile directive not allowed in ";
+ }
+ ap_pid_fname = arg;
+ return NULL;
+}
+
+static const char *set_scoreboard(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_scoreboard_fname = arg;
+ return NULL;
+}
+
+static const char *set_lockfile(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ lock_fname = arg;
+ return NULL;
+}
+
+static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_daemons_to_start = atoi(arg);
+ return NULL;
+}
+
+static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ min_spare_threads = atoi(arg);
+ if (min_spare_threads <= 0) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "WARNING: detected MinSpareThreads set to non-positive.");
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "Resetting to 1 to avoid almost certain Apache failure.");
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "Please read the documentation.");
+ min_spare_threads = 1;
+ }
+
+ return NULL;
+}
+
+static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ max_spare_threads = atoi(arg);
+ return NULL;
+}
+
+static const char *set_server_limit (cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_daemons_limit = atoi(arg);
+ if (ap_daemons_limit > HARD_SERVER_LIMIT) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "WARNING: MaxClients of %d exceeds compile time limit "
+ "of %d servers,", ap_daemons_limit, HARD_SERVER_LIMIT);
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ " lowering MaxClients to %d. To increase, please "
+ "see the", HARD_SERVER_LIMIT);
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ " HARD_SERVER_LIMIT define in %s.",
+ AP_MPM_HARD_LIMITS_FILE);
+ ap_daemons_limit = HARD_SERVER_LIMIT;
+ }
+ else if (ap_daemons_limit < 1) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "WARNING: Require MaxClients > 0, setting to 1");
+ ap_daemons_limit = 1;
+ }
+ return NULL;
+}
+
+static const char *set_threads_per_child (cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_threads_per_child = atoi(arg);
+ if (ap_threads_per_child > HARD_THREAD_LIMIT) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "WARNING: ThreadsPerChild of %d exceeds compile time "
+ "limit of %d threads,", ap_threads_per_child,
+ HARD_THREAD_LIMIT);
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ " lowering ThreadsPerChild to %d. To increase, please"
+ " see the", HARD_THREAD_LIMIT);
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ " HARD_THREAD_LIMIT define in %s.",
+ AP_MPM_HARD_LIMITS_FILE);
+ ap_threads_per_child = HARD_THREAD_LIMIT;
+ }
+ else if (ap_threads_per_child < 1) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+ "WARNING: Require ThreadsPerChild > 0, setting to 1");
+ ap_threads_per_child = 1;
+ }
+ return NULL;
+}
+
+static const char *set_max_requests(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ ap_max_requests_per_child = atoi(arg);
+
+ return NULL;
+}
+
+static const char *set_coredumpdir (cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ apr_finfo_t finfo;
+ const char *fname;
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ fname = ap_server_root_relative(cmd->pool, arg);
+ if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS)
+ || (finfo.filetype != APR_DIR)) {
+ return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
+ " does not exist or is not a directory", NULL);
+ }
+ apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
+ return NULL;
+}
+
+static const char *set_accept_lock_mech(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (!strcasecmp(arg, "default")) {
+ accept_lock_mech = APR_LOCK_DEFAULT;
+ }
+#if APR_HAS_FLOCK_SERIALIZE
+ else if (!strcasecmp(arg, "flock")) {
+ accept_lock_mech = APR_LOCK_FLOCK;
+ }
+#endif
+#if APR_HAS_FCNTL_SERIALIZE
+ else if (!strcasecmp(arg, "fcntl")) {
+ accept_lock_mech = APR_LOCK_FCNTL;
+ }
+#endif
+#if APR_HAS_SYSVSEM_SERIALIZE
+ else if (!strcasecmp(arg, "sysvsem")) {
+ accept_lock_mech = APR_LOCK_SYSVSEM;
+ }
+#endif
+#if APR_HAS_PROC_PTHREAD_SERIALIZE
+ else if (!strcasecmp(arg, "proc_pthread")) {
+ accept_lock_mech = APR_LOCK_PROC_PTHREAD;
+ }
+#endif
+ else {
+ return apr_pstrcat(cmd->pool, arg, " is an invalid mutex mechanism; valid "
+ "ones for this platform are: default"
+#if APR_HAS_FLOCK_SERIALIZE
+ ", flock"
+#endif
+#if APR_HAS_FCNTL_SERIALIZE
+ ", fcntl"
+#endif
+#if APR_HAS_SYSVSEM_SERIALIZE
+ ", sysvsem"
+#endif
+#if APR_HAS_PROC_PTHREAD_SERIALIZE
+ ", proc_pthread"
+#endif
+ , NULL);
+ }
+ return NULL;
+}
+
+static const command_rec worker_cmds[] = {
+UNIX_DAEMON_COMMANDS
+LISTEN_COMMANDS
+AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF,
+ "A file for logging the server process ID"),
+AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF,
+ "A file for Apache to maintain runtime process management information"),
+AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF,
+ "The lockfile used when Apache needs to lock the accept() call"),
+AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
+ "Number of child processes launched at server startup"),
+AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
+ "Minimum number of idle children, to handle request spikes"),
+AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
+ "Maximum number of idle children"),
+AP_INIT_TAKE1("MaxClients", set_server_limit, NULL, RSRC_CONF,
+ "Maximum number of children alive at the same time"),
+AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
+ "Number of threads each child creates"),
+AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF,
+ "Maximum number of requests a particular child serves before dying."),
+AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF,
+ "The location of the directory Apache changes to before dumping core"),
+AP_INIT_TAKE1("AcceptMutex", set_accept_lock_mech, NULL, RSRC_CONF,
+ "The system mutex implementation to use for the accept mutex"),
+{ NULL }
+};
+
+module AP_MODULE_DECLARE_DATA mpm_worker_module = {
+ MPM20_MODULE_STUFF,
+ NULL, /* hook to run before apache parses args */
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ worker_cmds, /* command apr_table_t */
+ worker_hooks /* register_hooks */
+};
+
diff --git a/server/util_time.c b/server/util_time.c
new file mode 100644
index 00000000000..3db076bceab
--- /dev/null
+++ b/server/util_time.c
@@ -0,0 +1,175 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+#include "util_time.h"
+
+/* Cache for exploded values of recent timestamps
+ */
+
+struct exploded_time_cache_element {
+ apr_int64_t t;
+ apr_exploded_time_t xt;
+ apr_int64_t t_validate; /* please see comments in cached_explode() */
+};
+
+/* the "+ 1" is for the current second: */
+#define TIME_CACHE_SIZE (AP_TIME_RECENT_THRESHOLD + 1)
+
+static struct exploded_time_cache_element exploded_cache_localtime[TIME_CACHE_SIZE];
+static struct exploded_time_cache_element exploded_cache_gmt[TIME_CACHE_SIZE];
+
+
+static apr_status_t cached_explode(apr_exploded_time_t *xt, apr_time_t t,
+ struct exploded_time_cache_element *cache,
+ int use_gmt)
+{
+ apr_int64_t seconds = t / APR_USEC_PER_SEC;
+ struct exploded_time_cache_element *cache_element =
+ &(cache[seconds % TIME_CACHE_SIZE]);
+ struct exploded_time_cache_element cache_element_snapshot;
+
+ /* The cache is implemented as a ring buffer. Each second,
+ * it uses a different element in the buffer. The timestamp
+ * in the element indicates whether the element contains the
+ * exploded time for the current second (vs the time
+ * 'now - AP_TIME_RECENT_THRESHOLD' seconds ago). If the
+ * cached value is for the current time, we use it. Otherwise,
+ * we compute the apr_exploded_time_t and store it in this
+ * cache element. Note that the timestamp in the cache
+ * element is updated only after the exploded time. Thus
+ * if two threads hit this cache element simultaneously
+ * at the start of a new second, they'll both explode the
+ * time and store it. I.e., the writers will collide, but
+ * they'll be writing the same value.
+ */
+ if (cache_element->t >= seconds) {
+ /* There is an intentional race condition in this design:
+ * in a multithreaded app, one thread might be reading
+ * from this cache_element to resolve a timestamp from
+ * TIME_CACHE_SIZE seconds ago at the same time that
+ * another thread is copying the exploded form of the
+ * current time into the same cache_element. (I.e., the
+ * first thread might hit this element of the ring buffer
+ * just as the element is being recycled.) This can
+ * also happen at the start of a new second, if a
+ * reader accesses the cache_element after a writer
+ * has updated cache_element.t but before the writer
+ * has finished updating the whole cache_element.
+ *
+ * Rather than trying to prevent this race condition
+ * with locks, we allow it to happen and then detect
+ * and correct it. The detection works like this:
+ * Step 1: Take a "snapshot" of the cache element by
+ * copying it into a temporary buffer.
+ * Step 2: Check whether the snapshot contains consistent
+ * data: the timestamps at the start and end of
+ * the cache_element should both match the 'seconds'
+ * value that we computed from the input time.
+ * If these three don't match, then the snapshot
+ * shows the cache_element in the middle of an
+ * update, and its contents are invalid.
+ * Step 3: If the snapshot is valid, use it. Otherwise,
+ * just give up on the cache and explode the
+ * input time.
+ */
+ memcpy(&cache_element_snapshot, cache_element,
+ sizeof(struct exploded_time_cache_element));
+ if ((seconds != cache_element_snapshot.t) ||
+ (seconds != cache_element_snapshot.t_validate)) {
+ /* Invalid snapshot */
+ if (use_gmt) {
+ return apr_explode_gmt(xt, t);
+ }
+ else {
+ return apr_explode_localtime(xt, t);
+ }
+ }
+ else {
+ /* Valid snapshot */
+ memcpy(xt, &(cache_element_snapshot.xt),
+ sizeof(apr_exploded_time_t));
+ }
+ }
+ else {
+ apr_status_t r;
+ if (use_gmt) {
+ r = apr_explode_gmt(xt, t);
+ }
+ else {
+ r = apr_explode_localtime(xt, t);
+ }
+ if (!APR_STATUS_IS_SUCCESS(r)) {
+ return r;
+ }
+ cache_element->t = seconds;
+ memcpy(&(cache_element->xt), xt, sizeof(apr_exploded_time_t));
+ cache_element->t_validate = seconds;
+ }
+ xt->tm_usec = t % APR_USEC_PER_SEC;
+ return APR_SUCCESS;
+}
+
+
+AP_DECLARE(apr_status_t) ap_explode_recent_localtime(apr_exploded_time_t * tm,
+ apr_time_t t)
+{
+ return cached_explode(tm, t, exploded_cache_localtime, 0);
+}
+
+AP_DECLARE(apr_status_t) ap_explode_recent_gmt(apr_exploded_time_t * tm,
+ apr_time_t t)
+{
+ return cached_explode(tm, t, exploded_cache_gmt, 1);
+}
diff --git a/support/abs.dsp b/support/abs.dsp
new file mode 100644
index 00000000000..cd8467a5947
--- /dev/null
+++ b/support/abs.dsp
@@ -0,0 +1,131 @@
+# Microsoft Developer Studio Project File - Name="abs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=abs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "abs.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "abs.mak" CFG="abs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "abs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "abs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "USE_SSL" /Fd"Release/abs" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /map /machine:I386 /libpath:"../srclib/openssl/out32dll"
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /map /machine:I386 /libpath:"../srclib/openssl/out32dll"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "USE_SSL" /Fd"Debug/abs" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386 /libpath:"../srclib/openssl/out32dll"
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386 /libpath:"../srclib/openssl/out32dll"
+
+!ENDIF
+
+# Begin Target
+
+# Name "abs - Win32 Release"
+# Name "abs - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\ab.c
+
+!IF "$(CFG)" == "abs - Win32 Release"
+# ADD CPP /Fo"Release/abs.obj"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+# ADD CPP /Fo"Debug/abs.obj"
+
+!ENDIF
+# End Source File
+# Begin Source File
+
+SOURCE=.\abs.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\build\win32\win32ver.awk
+
+".\abs.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../build/win32/win32ver.awk ab "ApacheBench/SSL Utility" ../include/ap_release.h > .\abs.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\build\win32\win32ver.awk
+
+".\abs.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../build/win32/win32ver.awk ab "ApacheBench/SSL Utility" ../include/ap_release.h > .\abs.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/support/config.m4 b/support/config.m4
new file mode 100644
index 00000000000..ce377479b69
--- /dev/null
+++ b/support/config.m4
@@ -0,0 +1,45 @@
+
+
+htpasswd_LTFLAGS=""
+htdigest_LTFLAGS=""
+rotatelogs_LTFLAGS=""
+logresolve_LTFLAGS=""
+ab_LTFLAGS=""
+
+dnl XXX Should we change the foo_LTFLAGS="-static" settings below
+dnl to something like APR_ADDTO? -aaron
+
+AC_ARG_ENABLE(static-htpasswd,[ --enable-static-htpasswd Build a statically linked version of htpasswd],[
+if test "$enableval" = "yes" ; then
+ htpasswd_LTFLAGS="-static"
+fi
+])
+APACHE_SUBST(htpasswd_LTFLAGS)
+
+AC_ARG_ENABLE(static-htdigest,[ --enable-static-htdigest Build a statically linked version of htdigest],[
+if test "$enableval" = "yes" ; then
+ htdigest_LTFLAGS="-static"
+fi
+])
+APACHE_SUBST(htdigest_LTFLAGS)
+
+AC_ARG_ENABLE(static-rotatelogs,[ --enable-static-rotatelogs Build a statically linked version of rotatelogs],[
+if test "$enableval" = "yes" ; then
+ rotatelogs_LTFLAGS="-static"
+fi
+])
+APACHE_SUBST(rotatelogs_LTFLAGS)
+
+AC_ARG_ENABLE(static-logresolve,[ --enable-static-logresolve Build a statically linked version of logresolve],[
+if test "$enableval" = "yes" ; then
+ logresolve_LTFLAGS="-static"
+fi
+])
+APACHE_SUBST(logresolve_LTFLAGS)
+
+AC_ARG_ENABLE(static-ab,[ --enable-static-ab Build a statically linked version of ab],[
+if test "$enableval" = "yes" ; then
+ ab_LTFLAGS="-static"
+fi
+])
+APACHE_SUBST(ab_LTFLAGS)
diff --git a/support/list_hooks.pl b/support/list_hooks.pl
new file mode 100755
index 00000000000..c52c5671424
--- /dev/null
+++ b/support/list_hooks.pl
@@ -0,0 +1,77 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Carp;
+
+my $path=shift;
+
+findInDir($path);
+
+foreach my $hook (sort keys %::Hooks) {
+ my $h=$::Hooks{$hook};
+ for my $x (qw(declared implemented type args)) {
+ croak "$hook datum '$x' missing" if !exists $h->{$x};
+ }
+ print "$hook\n";
+ print " declared in $h->{declared}\n";
+ print " implemented in $h->{implemented}\n";
+ print " type is $h->{type}\n";
+ print " $h->{ret} $hook($h->{args})\n";
+ print "\n";
+}
+
+sub findInDir {
+ my $path=shift;
+
+ local(*D);
+ opendir(D,$path) || croak "Can't open $path: $!";
+ while(my $f=readdir D) {
+ next if $f=~/^\./;
+ my $file="$path/$f";
+
+ if(-d $file) {
+ findInDir($file);
+ next;
+ }
+ next if $file !~ /\.[ch]$/;
+
+ scanFile($file);
+ }
+ closedir D;
+}
+
+sub scanFile {
+ my $file=shift;
+
+# print "scanning $file\n";
+
+ open(F,$file) || croak "Can't open $file: $!";
+ while() {
+ next if /\#define/;
+ next if /\@deffunc/;
+ if(/AP_DECLARE_HOOK\((.*)\)/) {
+ my $def=$1;
+ my($ret,$name,$args)=$def=~/([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*\((.*)\)/;
+ croak "Don't understand $def in $file" if !defined $args;
+# print "found $ret $name($args) in $file\n";
+
+ croak "$name declared twice! ($_)"
+ if exists $::Hooks{$name}->{declared};
+ $::Hooks{$name}->{declared}=$file;
+ $::Hooks{$name}->{ret}=$ret;
+ $::Hooks{$name}->{args}=$args;
+ }
+ if(/AP_IMPLEMENT_HOOK_()(VOID)\(([^,\s]+)/
+ || /AP_IMPLEMENT(_OPTIONAL|)_HOOK_(.*?)\([^,]+?\s*,\s*([^,\s]+)/) {
+ my($type,$name)=($1 ? "OPTIONAL $2" : $2,$3);
+
+# print "found $name $type in $file\n";
+
+ croak "$name implemented twice ($::Hooks{$name}->{implemented} and $file) ($_)"
+ if exists $::Hooks{$name}->{implemented};
+ $::Hooks{$name}->{implemented}=$file;
+ $::Hooks{$name}->{type}=$type;
+ }
+ }
+}
diff --git a/support/win32/.cvsignore b/support/win32/.cvsignore
new file mode 100644
index 00000000000..7658ff55256
--- /dev/null
+++ b/support/win32/.cvsignore
@@ -0,0 +1,3 @@
+Release
+Debug
+*.plg
diff --git a/support/win32/ApacheMonitor.c b/support/win32/ApacheMonitor.c
new file mode 100644
index 00000000000..156f896abc4
--- /dev/null
+++ b/support/win32/ApacheMonitor.c
@@ -0,0 +1,1367 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/* ====================================================================
+ * ApacheService.c Simple program to manage and monitor Apache services.
+ *
+ * Contributed by Mladen Turk
+ *
+ * 05 Aug 2001
+ * ====================================================================
+ */
+
+#define _WIN32_WINNT 0x0400
+#ifndef STRICT
+#define STRICT
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include "ApacheMonitor.h"
+
+
+#define OS_VERSION_WINNT 1
+#define OS_VERSION_WIN9X 2
+#define OS_VERSION_WIN2K 3
+/* Should be enough */
+#define MAX_APACHE_SERVICES 128
+
+#define WM_TRAYMESSAGE (WM_APP+1)
+#define WM_UPDATEMESSAGE (WM_USER+1)
+#define SERVICE_APACHE_RESTART 128
+#define XBITMAP 16
+#define YBITMAP 16
+#define MAX_LOADSTRING 100
+
+#ifndef SERVICE_RUNS_IN_SYSTEM_PROCESS
+#define SERVICE_RUNS_IN_SYSTEM_PROCESS 0x00000001
+
+typedef struct _SERVICE_STATUS_PROCESS {
+ DWORD dwServiceType;
+ DWORD dwCurrentState;
+ DWORD dwControlsAccepted;
+ DWORD dwWin32ExitCode;
+ DWORD dwServiceSpecificExitCode;
+ DWORD dwCheckPoint;
+ DWORD dwWaitHint;
+ DWORD dwProcessId;
+ DWORD dwServiceFlags;
+} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;
+
+typedef enum _SC_STATUS_TYPE {
+ SC_STATUS_PROCESS_INFO = 0
+} SC_STATUS_TYPE;
+
+#endif
+
+typedef BOOL (WINAPI *QUERYSERVICESTATUSEX)(SC_HANDLE, SC_STATUS_TYPE,
+ LPBYTE, DWORD, LPDWORD);
+
+typedef struct _st_APACHE_SERVICE
+{
+ LPSTR szServiceName;
+ LPSTR szDisplayName;
+ LPSTR szDescription;
+ LPSTR szImagePath;
+ DWORD dwPid;
+} ST_APACHE_SERVICE;
+
+/* Global variables */
+HINSTANCE ap_hInstance = NULL;
+HWND ap_hwndAboutDlg = NULL;
+TCHAR szTitle[MAX_LOADSTRING]; /* The title bar text */
+TCHAR szWindowClass[MAX_LOADSTRING]; /* Window Class Name */
+HICON ap_icoStop;
+HICON ap_icoRun;
+UINT ap_uiTaskbarCreated;
+DWORD ap_OSVersion;
+BOOL dlgAboutOn = FALSE;
+BOOL dlgServiceOn = FALSE;
+ST_APACHE_SERVICE ap_stServices[MAX_APACHE_SERVICES];
+
+HBITMAP hbmpStart, hbmpStop;
+HBITMAP hbmpPicture, hbmpOld;
+HWND ap_hServiceDlg;
+BOOL ap_rescanServices;
+HWND ap_hServiceDlg;
+
+
+void ap_ClearServicesSt()
+{
+ int i;
+ for (i = 0; i < MAX_APACHE_SERVICES; i++)
+ {
+ if (ap_stServices[i].szServiceName)
+ free(ap_stServices[i].szServiceName);
+ if (ap_stServices[i].szDisplayName)
+ free(ap_stServices[i].szDisplayName);
+ if (ap_stServices[i].szDescription)
+ free(ap_stServices[i].szDescription);
+ if (ap_stServices[i].szImagePath)
+ free(ap_stServices[i].szImagePath);
+
+ }
+ ZeroMemory(ap_stServices, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+
+}
+
+void ErrorMessage(DWORD dwError)
+{
+ LPVOID lpMsgBuf;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dwError == ERROR_SUCCESS ? GetLastError() : dwError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+ MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONERROR);
+ LocalFree(lpMsgBuf);
+
+}
+
+LPTSTR GetStringRes(int id)
+{
+ static TCHAR buffer[MAX_PATH];
+
+ buffer[0] = 0;
+ LoadString(GetModuleHandle (NULL), id, buffer, MAX_PATH);
+ return buffer;
+}
+
+BOOL GetSystemOSVersion(LPSTR szVersion, LPDWORD dwVersion)
+{
+ OSVERSIONINFOEX osvi;
+ BOOL bOsVersionInfoEx;
+ char szBuff[256];
+ HKEY hKey;
+ char szProductType[80];
+ DWORD dwBufLen;
+
+ /*
+ Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+ If that fails, try using the OSVERSIONINFO structure.
+ */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi)))
+ {
+ /* If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. */
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *) &osvi))
+ return FALSE;
+ }
+
+ switch (osvi.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_NT:
+ /* Test for the product. */
+ if (szVersion!= NULL)
+ {
+ if (osvi.dwMajorVersion <= 4)
+ strcpy(szVersion, "MS Windows NT ");
+ else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ strcpy(szVersion, "MS Windows 2000 ");
+ else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ strcpy(szVersion, "Whistler ");
+ /* Test for product type.*/
+#ifdef VER_VORKSTATION_NT
+ if (bOsVersionInfoEx)
+ {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ {
+#ifdef VER_SUITE_PERSONAL
+ if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
+ strcat(szVersion, "Personal ");
+ else
+#endif
+ strcat(szVersion, "Professional ");
+ }
+ else if (osvi.wProductType == VER_NT_SERVER)
+ {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+ strcat(szVersion, "DataCenter Server ");
+ else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+ strcat(szVersion, "Advanced Server ");
+ else
+ strcat(szVersion, "Server ");
+ }
+ }
+ else
+ {
+#endif
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_QUERY_VALUE, &hKey);
+ RegQueryValueEx(hKey, "ProductType", NULL, NULL,
+ (LPBYTE) szProductType, &dwBufLen);
+ RegCloseKey(hKey);
+ if (lstrcmpi("WINNT", szProductType) == 0)
+ strcat(szVersion, "Workstation ");
+ if (lstrcmpi("SERVERNT", szProductType) == 0)
+ strcat(szVersion, "Server ");
+#ifdef VER_VORKSTATION_NT
+ }
+#endif
+ /* Get version, service pack (if any), and build number. */
+ if (osvi.dwMajorVersion <= 4)
+ {
+ sprintf(szBuff, "version %d.%d %s (Build-%d)\n",
+ osvi.dwMajorVersion,
+ osvi.dwMinorVersion,
+ osvi.szCSDVersion,
+ osvi.dwBuildNumber & 0xFFFF);
+ }
+ else
+ {
+ sprintf(szBuff, "%s (Build-%d)\n",
+ osvi.szCSDVersion,
+ osvi.dwBuildNumber & 0xFFFF);
+ }
+ strcat(szVersion, szBuff);
+ }
+ else if (dwVersion != NULL)
+ {
+ if (osvi.dwMajorVersion <= 4)
+ *dwVersion = OS_VERSION_WINNT;
+ else if (osvi.dwMajorVersion == 5)
+ *dwVersion = OS_VERSION_WIN2K;
+ else
+ return FALSE;
+
+ }
+ break;
+
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (szVersion != NULL)
+ {
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
+ {
+ strcpy(szVersion, "MS Windows 95 ");
+ if (osvi.szCSDVersion[1] == 'C')
+ strcat(szVersion, "OSR2 ");
+ }
+
+ if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
+ {
+ strcpy(szVersion, "MS Windows 98 ");
+ if (osvi.szCSDVersion[1] == 'A')
+ strcat(szVersion, "SE ");
+ }
+
+ if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
+ {
+ strcpy(szVersion, "MS Windows Me ");
+ }
+ }
+ if (dwVersion != NULL)
+ *dwVersion = OS_VERSION_WIN9X;
+
+ break;
+
+ case VER_PLATFORM_WIN32s:
+ if (szVersion != NULL)
+ strcpy(szVersion, "Microsoft Win32s ");
+ if (dwVersion != NULL)
+ *dwVersion = OS_VERSION_WIN9X;
+ break;
+ default:
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+static VOID ShowNotifyIcon(HWND hWnd, DWORD dwMessage)
+{
+
+ NOTIFYICONDATA nid;
+ int i = 0, n = 0;
+
+ ZeroMemory(&nid,sizeof(nid));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hWnd;
+ nid.uID = 0xFF;
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_TRAYMESSAGE;
+
+ while (ap_stServices[i].szServiceName != NULL)
+ {
+ if (ap_stServices[i].dwPid != 0)
+ ++n;
+ ++i;
+ }
+ if (dwMessage != NIM_DELETE)
+ {
+ if (n)
+ nid.hIcon = ap_icoRun;
+ else
+ nid.hIcon = ap_icoStop;
+ }
+ else
+ nid.hIcon = NULL;
+
+ sprintf(nid.szTip, "Running: %d Services", n);
+ Shell_NotifyIcon(dwMessage, &nid);
+
+}
+
+void ShowTryPopupMenu(HWND hWnd)
+{
+ /* create popup menu */
+ HMENU hMenu = CreatePopupMenu();
+ POINT pt;
+
+ if (hMenu)
+ {
+ AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "&About...");
+ AppendMenu(hMenu, MF_STRING, IDM_RESTORE, "&Show Services...");
+ AppendMenu(hMenu, MF_SEPARATOR, 0, "");
+ AppendMenu(hMenu, MF_STRING, IDM_EXIT, "&Exit...");
+
+ GetCursorPos(&pt);
+ SetForegroundWindow(NULL);
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
+ }
+}
+
+BOOL CenterWindow(HWND hwndChild)
+{
+ RECT rChild, rWorkArea;
+ int wChild, hChild;
+ int xNew, yNew;
+ BOOL bResult;
+
+ /* Get the Height and Width of the child window */
+ GetWindowRect(hwndChild, &rChild);
+ wChild = rChild.right - rChild.left;
+ hChild = rChild.bottom - rChild.top;
+
+ /* Get the limits of the 'workarea' */
+ bResult = SystemParametersInfo(
+ SPI_GETWORKAREA, /* system parameter to query or set */
+ sizeof(RECT),
+ &rWorkArea,
+ 0);
+ if (!bResult) {
+ rWorkArea.left = rWorkArea.top = 0;
+ rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
+ rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ /* Calculate new X position, then adjust for workarea */
+ xNew = (rWorkArea.right - wChild)/2;
+ yNew = (rWorkArea.bottom - hChild)/2;
+ return SetWindowPos (hwndChild, HWND_TOP, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+}
+
+static void addItem(HWND hDlg, LPSTR lpStr, HBITMAP hBmp)
+{
+ int nItem;
+
+ nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr);
+ SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp);
+}
+
+
+BOOL RunAndForgetConsole(LPTSTR szCmdLine,
+ LPDWORD nRetValue,
+ BOOL showConsole)
+{
+
+
+ STARTUPINFO stInfo;
+ PROCESS_INFORMATION prInfo;
+ BOOL bResult;
+ ZeroMemory(&stInfo, sizeof(stInfo));
+ stInfo.cb = sizeof(stInfo);
+ stInfo.dwFlags = STARTF_USESHOWWINDOW;
+ stInfo.wShowWindow = showConsole ? SW_SHOWNORMAL : SW_HIDE;
+
+ bResult = CreateProcess(NULL,
+ szCmdLine,
+ NULL,
+ NULL,
+ TRUE,
+ CREATE_NEW_CONSOLE ,
+ NULL,
+ NULL ,
+ &stInfo,
+ &prInfo);
+ if (nRetValue)
+ *nRetValue = GetLastError();
+
+ CloseHandle(prInfo.hThread);
+ CloseHandle(prInfo.hProcess);
+ if (!bResult)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+BOOL ApacheManageService(LPCSTR szServiceName, LPCSTR szImagePath, DWORD dwCommand)
+{
+
+ CHAR szBuf[MAX_PATH];
+ LPSTR sPos;
+ DWORD retCode;
+ BOOL retValue;
+ BOOL ntService = TRUE;
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+ SERVICE_STATUS schSStatus;
+ LPSTR *args;
+ int ticks;
+
+ if (ap_OSVersion == OS_VERSION_WIN9X)
+ {
+ sPos = strstr(szImagePath, "-k start");
+ if (sPos)
+ {
+ lstrcpyn(szBuf, szImagePath, sPos - szImagePath);
+ switch (dwCommand)
+ {
+ case SERVICE_CONTROL_STOP:
+ lstrcat(szBuf, " -k stop -n ");
+ break;
+ case SERVICE_CONTROL_CONTINUE:
+ lstrcat(szBuf, " -k start -n ");
+ break;
+ case SERVICE_APACHE_RESTART:
+ lstrcat(szBuf, " -k restart -n ");
+ break;
+ case SERVICE_CONTROL_SHUTDOWN:
+ lstrcat(szBuf, " -k uninstall -n ");
+ break;
+ default:
+ return FALSE;
+ }
+ lstrcat(szBuf, szServiceName);
+ }
+ else
+ return FALSE;
+ if (!RunAndForgetConsole(szBuf, &retCode, FALSE))
+ {
+ ErrorMessage(retCode);
+ return FALSE;
+ }
+ }
+ else
+ {
+ sPos = strstr(szImagePath, "--ntservice");
+ if (!sPos)
+ {
+ sPos = strstr(szImagePath, "-k runservice");
+ ntService = FALSE;
+ }
+ if (sPos)
+ {
+ lstrcpyn(szBuf, szImagePath, sPos - szImagePath);
+ if (dwCommand == SERVICE_CONTROL_SHUTDOWN)
+ {
+ lstrcat(szBuf, " -k uninstall -n ");
+ lstrcat(szBuf, szServiceName);
+ if (!RunAndForgetConsole(szBuf, &retCode, FALSE))
+ {
+ ErrorMessage(retCode);
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+ }
+ else
+ return FALSE;
+ schSCManager = OpenSCManager(
+ NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS
+ );
+ if (!schSCManager)
+ return FALSE;
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
+ if (schService != NULL)
+ {
+ retValue = FALSE;
+ switch (dwCommand)
+ {
+ case SERVICE_CONTROL_STOP:
+ if(ControlService(schService, SERVICE_CONTROL_STOP, &schSStatus))
+ {
+ Sleep(1000);
+ while (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
+ Sleep(1000);
+ else
+ break;
+ }
+ }
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+ if(schSStatus.dwCurrentState == SERVICE_STOPPED)
+ retValue = TRUE;
+ }
+ break;
+ case SERVICE_CONTROL_CONTINUE:
+ args = (char **)malloc(3 * sizeof(char*));
+ args[0] = szBuf;
+ if (ntService)
+ args[1] = "--ntservice";
+ else
+ {
+ args[1] = "-k";
+ args[2] = "runservice";
+ }
+ if(StartService(schService, ntService ? 2 : 3, args))
+ {
+ Sleep(1000);
+ while (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
+ Sleep(1000);
+ else
+ break;
+ }
+ }
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+ if(schSStatus.dwCurrentState == SERVICE_RUNNING)
+ retValue = TRUE;
+ }
+ /* is this OK to do? */
+ free(args);
+ break;
+ case SERVICE_APACHE_RESTART:
+ if(ControlService(schService, SERVICE_APACHE_RESTART, &schSStatus))
+ {
+ ticks = 60;
+ while(schSStatus.dwCurrentState == SERVICE_START_PENDING)
+ {
+ Sleep(1000);
+ if(!QueryServiceStatus(schService, &schSStatus))
+ {
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return FALSE;
+ }
+ if (!--ticks)
+ break;
+ }
+ }
+ if(schSStatus.dwCurrentState == SERVICE_RUNNING)
+ retValue = TRUE;
+ break;
+ }
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return retValue;
+
+ }
+ else
+ ap_rescanServices = TRUE;
+
+ CloseServiceHandle(schSCManager);
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+BOOL IsServiceRunning(LPCSTR szServiceName, LPDWORD lpdwPid)
+{
+
+ DWORD dwPid, dwBytes;
+ HWND hWnd;
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+ SERVICE_STATUS schSStatus;
+ SERVICE_STATUS_PROCESS schSProcess;
+ HANDLE hAdvapi;
+ QUERYSERVICESTATUSEX pQueryServiceStatusEx = NULL;
+
+ if (ap_OSVersion == OS_VERSION_WIN9X)
+ {
+ hWnd = FindWindow("ApacheWin95ServiceMonitor", szServiceName);
+ if (hWnd && GetWindowThreadProcessId(hWnd, &dwPid))
+ {
+ *lpdwPid = dwPid;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+
+ dwPid = 0;
+ schSCManager = OpenSCManager(
+ NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS
+ );
+ if (!schSCManager)
+ return FALSE;
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_QUERY_STATUS);
+ if (schService != NULL)
+ {
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+
+ dwPid = schSStatus.dwCurrentState;
+ if (lpdwPid)
+ *lpdwPid = 1;
+ }
+ if (ap_OSVersion == OS_VERSION_WIN2K)
+ {
+ hAdvapi = LoadLibrary("ADVAPI32.DLL");
+ if (hAdvapi != NULL)
+ pQueryServiceStatusEx = (QUERYSERVICESTATUSEX)GetProcAddress(hAdvapi,
+ "QueryServiceStatusEx");
+ if (hAdvapi != NULL && pQueryServiceStatusEx != NULL)
+ {
+ if (pQueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&schSProcess, sizeof(SERVICE_STATUS_PROCESS), &dwBytes))
+ {
+ dwPid = schSProcess.dwCurrentState;
+ if (lpdwPid)
+ *lpdwPid = schSProcess.dwProcessId;
+ }
+ }
+ if (hAdvapi != NULL)
+ FreeLibrary(hAdvapi);
+ }
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
+ }
+ else
+ ap_rescanServices = TRUE;
+
+ CloseServiceHandle(schSCManager);
+ return FALSE;
+
+ }
+
+ return FALSE;
+}
+
+BOOL FindRunningServices()
+{
+ int i = 0;
+ DWORD dwPid;
+ BOOL rv = FALSE;
+ while (ap_stServices[i].szServiceName != NULL)
+ {
+ if (!IsServiceRunning(ap_stServices[i].szServiceName, &dwPid))
+ dwPid = 0;
+ if (ap_stServices[i].dwPid != dwPid)
+ rv = TRUE;
+ ap_stServices[i].dwPid = dwPid;
+ ++i;
+ }
+ return rv;
+}
+
+BOOL GetApacheServicesStatus()
+{
+
+ CHAR szKey[MAX_PATH];
+ CHAR achKey[MAX_PATH];
+ CHAR szImagePath[MAX_PATH];
+ CHAR szBuf[MAX_PATH];
+
+ HKEY hKey, hSubKey;
+ DWORD retCode, rv, dwKeyType;
+ DWORD dwBufLen = MAX_PATH;
+
+ int i, stPos = 0;
+ ap_rescanServices = FALSE;
+
+ retCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "System\\CurrentControlSet\\Services\\",
+ 0, KEY_READ, &hKey);
+ if (retCode != ERROR_SUCCESS)
+ {
+ ErrorMessage(retCode);
+ return FALSE;
+ }
+ ap_ClearServicesSt();
+ for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
+ {
+
+ retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
+ if (retCode == ERROR_SUCCESS)
+ {
+ lstrcpy(szKey, "System\\CurrentControlSet\\Services\\");
+ lstrcat(szKey, achKey);
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0,
+ KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
+ {
+ dwBufLen = MAX_PATH;
+ rv = RegQueryValueEx(hSubKey, "ImagePath", NULL,
+ &dwKeyType, szImagePath, &dwBufLen);
+
+ if (rv == ERROR_SUCCESS && (dwKeyType == REG_SZ || dwKeyType == REG_EXPAND_SZ) && dwBufLen)
+ {
+ lstrcpy(szBuf, szImagePath);
+ CharLower(szBuf);
+ if (strstr(szBuf, "\\apache.exe") != NULL)
+ {
+ ap_stServices[stPos].szServiceName = strdup(achKey);
+ ap_stServices[stPos].szImagePath = strdup(szImagePath);
+ dwBufLen = MAX_PATH;
+ if (RegQueryValueEx(hSubKey, "Description", NULL,
+ &dwKeyType, szBuf, &dwBufLen) == ERROR_SUCCESS)
+ ap_stServices[stPos].szDescription = strdup(szBuf);
+
+ dwBufLen = MAX_PATH;
+ if (RegQueryValueEx(hSubKey, "DisplayName", NULL,
+ &dwKeyType, szBuf, &dwBufLen) == ERROR_SUCCESS)
+ ap_stServices[stPos].szDisplayName= strdup(szBuf);
+ ++stPos;
+ if (stPos >= MAX_APACHE_SERVICES)
+ retCode = !ERROR_SUCCESS;
+ }
+ }
+ RegCloseKey(hSubKey);
+ }
+ }
+ }
+ RegCloseKey(hKey);
+ FindRunningServices();
+ return TRUE;
+}
+
+LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+
+ CHAR tchBuffer[MAX_PATH];
+ CHAR tsbBuffer[MAX_PATH];
+ CHAR szBuf[64];
+ HWND hListBox;
+ static HWND hStatusBar;
+ TEXTMETRIC tm;
+ int i, y;
+ HDC hdcMem;
+ LPMEASUREITEMSTRUCT lpmis;
+ LPDRAWITEMSTRUCT lpdis;
+ RECT rcBitmap;
+ UINT nItem;
+
+ switch (message)
+ {
+
+ case WM_INITDIALOG:
+ ShowWindow(hDlg, SW_HIDE);
+ ap_hServiceDlg = hDlg;
+ hbmpStart = LoadBitmap(ap_hInstance, MAKEINTRESOURCE(IDB_BMPRUN));
+ hbmpStop = LoadBitmap(ap_hInstance, MAKEINTRESOURCE(IDB_BMPSTOP));
+
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ hStatusBar = CreateStatusWindow(SBT_TOOLTIPS | WS_CHILD | WS_VISIBLE,
+ "", hDlg, IDC_STATBAR);
+ if (GetApacheServicesStatus())
+ {
+ i = 0;
+ while (ap_stServices[i].szServiceName != NULL)
+ {
+ addItem(hListBox, ap_stServices[i].szDisplayName,
+ ap_stServices[i].dwPid == 0 ? hbmpStop : hbmpStart);
+ ++i;
+ }
+ }
+ CenterWindow(hDlg);
+ ShowWindow(hDlg, SW_SHOW);
+ SetFocus(hListBox);
+ SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+ return TRUE;
+ break;
+ case WM_UPDATEMESSAGE:
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), FALSE);
+ i = 0;
+ while (ap_stServices[i].szServiceName != NULL)
+ {
+ addItem(hListBox, ap_stServices[i].szDisplayName,
+ ap_stServices[i].dwPid == 0 ? hbmpStop : hbmpStart);
+ ++i;
+ }
+ SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+ /* Dirty hack to bring the window to the foreground */
+ SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetFocus(hListBox);
+ return TRUE;
+ break;
+ case WM_MEASUREITEM:
+
+ lpmis = (LPMEASUREITEMSTRUCT) lParam;
+ lpmis->itemHeight = 16;
+ return TRUE;
+
+ case WM_DRAWITEM:
+
+ lpdis = (LPDRAWITEMSTRUCT) lParam;
+ if (lpdis->itemID == -1)
+ {
+ break;
+ }
+ switch (lpdis->itemAction)
+ {
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+ hbmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem,
+ LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0);
+
+ hdcMem = CreateCompatibleDC(lpdis->hDC);
+ hbmpOld = SelectObject(hdcMem, hbmpPicture);
+
+ BitBlt(lpdis->hDC,
+ lpdis->rcItem.left, lpdis->rcItem.top,
+ lpdis->rcItem.right - lpdis->rcItem.left,
+ lpdis->rcItem.bottom - lpdis->rcItem.top,
+ hdcMem, 0, 0, SRCCOPY);
+ SendMessage(lpdis->hwndItem, LB_GETTEXT,
+ lpdis->itemID, (LPARAM) tchBuffer);
+
+ GetTextMetrics(lpdis->hDC, &tm);
+ y = (lpdis->rcItem.bottom + lpdis->rcItem.top -
+ tm.tmHeight) / 2;
+
+ SelectObject(hdcMem, hbmpOld);
+ DeleteDC(hdcMem);
+
+ rcBitmap.left = lpdis->rcItem.left + XBITMAP;
+ rcBitmap.top = lpdis->rcItem.top;
+ rcBitmap.right = lpdis->rcItem.right;
+ rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;
+
+ if (lpdis->itemState & ODS_SELECTED)
+ {
+ if (hbmpPicture == hbmpStop)
+ {
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), TRUE);
+
+ }
+ else if (hbmpPicture == hbmpStart)
+ {
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), FALSE);
+
+ }
+ i = 0;
+ while (ap_stServices[i].szServiceName != NULL)
+ {
+ if (lstrcmp(ap_stServices[i].szDisplayName, tchBuffer) == 0)
+ {
+ if (ap_stServices[i].szDescription)
+ lstrcpy(tsbBuffer, ap_stServices[i].szDescription);
+ else
+ lstrcpy(tsbBuffer, ap_stServices[i].szImagePath);
+ if (ap_stServices[i].dwPid != 0)
+ {
+ if (ap_stServices[i].dwPid & 0xFF000000)
+ sprintf(szBuf, " PID : 0x%08X", ap_stServices[i].dwPid);
+ else
+ sprintf(szBuf, " PID : %d", ap_stServices[i].dwPid);
+ lstrcat(tsbBuffer, szBuf);
+ }
+ SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)tsbBuffer);
+ break;
+ }
+ ++i;
+ }
+
+ SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
+ FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHTTEXT));
+ }
+ else
+ {
+ SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT));
+ SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
+ FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1));
+ }
+ TextOut(lpdis->hDC,
+ XBITMAP + 6,
+ y,
+ tchBuffer,
+ strlen(tchBuffer));
+ break;
+
+ case ODA_FOCUS:
+ break;
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDL_SERVICES:
+ switch (HIWORD(wParam))
+ {
+ case LBN_DBLCLK:
+ GetApacheServicesStatus();
+ SendMessage(hDlg, WM_UPDATEMESSAGE, 0, 0);
+ return TRUE;
+ }
+ break;
+ case IDOK:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ break;
+ case IDC_SSTART:
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR)
+ {
+ ApacheManageService(ap_stServices[nItem].szServiceName,
+ ap_stServices[nItem].szImagePath,
+ SERVICE_CONTROL_CONTINUE);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
+ return TRUE;
+ break;
+ case IDC_SSTOP:
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR)
+ {
+ ApacheManageService(ap_stServices[nItem].szServiceName,
+ ap_stServices[nItem].szImagePath,
+ SERVICE_CONTROL_STOP);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
+ return TRUE;
+ break;
+ case IDC_SRESTART:
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR)
+ {
+ ApacheManageService(ap_stServices[nItem].szServiceName,
+ ap_stServices[nItem].szImagePath,
+ SERVICE_APACHE_RESTART);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+ return TRUE;
+ break;
+ case IDC_SUNINSTALL:
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR)
+ {
+ ApacheManageService(ap_stServices[nItem].szServiceName,
+ ap_stServices[nItem].szImagePath,
+ SERVICE_CONTROL_SHUTDOWN);
+ }
+ ap_rescanServices = TRUE;
+ Button_Enable(GetDlgItem(hDlg, IDC_SUNINSTALL), TRUE);
+ return TRUE;
+ break;
+ }
+ break;
+ case WM_SIZE:
+ switch (LOWORD(wParam))
+ {
+ case SIZE_MINIMIZED:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ break;
+ }
+ break;
+ case WM_ERASEBKGND:
+
+ break;
+ case WM_CLOSE:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ case WM_DESTROY:
+ DeleteObject(hbmpStart);
+ DeleteObject(hbmpStop);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/* About Box from MS Generic Sample */
+LRESULT CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static HFONT hfontDlg; /* Font for dialog text */
+ static HFONT hFinePrint; /* Font for 'fine print' in dialog */
+ DWORD dwVerInfoSize; /* Size of version information block */
+ LPSTR lpVersion; /* String pointer to 'version' text */
+ DWORD dwVerHnd=0; /* An 'ignored' parameter, always '0' */
+ UINT uVersionLen;
+ WORD wRootLen;
+ BOOL bRetCode;
+ int i;
+ char szFullPath[256];
+ char szResult[256];
+ char szGetName[256];
+ char szVersion[256];
+ DWORD dwResult;
+
+ switch (message) {
+ case WM_INITDIALOG:
+ ShowWindow(hDlg, SW_HIDE);
+ ap_hwndAboutDlg = hDlg;
+
+ hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ VARIABLE_PITCH | FF_SWISS, "");
+ hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ VARIABLE_PITCH | FF_SWISS, "");
+
+ CenterWindow(hDlg);
+ GetModuleFileName(ap_hInstance, szFullPath, sizeof(szFullPath));
+
+ /* Now lets dive in and pull out the version information: */
+ dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
+ if (dwVerInfoSize) {
+ LPSTR lpstrVffInfo;
+ HANDLE hMem;
+ hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
+ lpstrVffInfo = GlobalLock(hMem);
+ GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
+ lstrcpy(szGetName, GetStringRes(IDS_VER_INFO_LANG));
+
+ wRootLen = lstrlen(szGetName); /* Save this position */
+
+ /* Set the title of the dialog: */
+ lstrcat(szGetName, "ProductName");
+ bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
+ (LPSTR)szGetName,
+ (LPVOID)&lpVersion,
+ (UINT *)&uVersionLen);
+
+ /* Notice order of version and string... */
+ lstrcpy(szResult, "About ");
+ lstrcat(szResult, lpVersion);
+
+ SetWindowText(hDlg, szResult);
+
+ /* Walk through the dialog items that we want to replace: */
+ for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++) {
+ GetDlgItemText(hDlg, i, szResult, sizeof(szResult));
+ szGetName[wRootLen] = (char)0;
+ lstrcat(szGetName, szResult);
+ uVersionLen = 0;
+ lpVersion = NULL;
+ bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
+ (LPSTR)szGetName,
+ (LPVOID)&lpVersion,
+ (UINT *)&uVersionLen);
+
+ if (bRetCode && uVersionLen && lpVersion) {
+ /* Replace dialog item text with version info */
+ lstrcpy(szResult, lpVersion);
+ SetDlgItemText(hDlg, i, szResult);
+ }
+ else
+ {
+ dwResult = GetLastError();
+
+ wsprintf(szResult, GetStringRes(IDS_VERSION_ERROR), dwResult);
+ SetDlgItemText(hDlg, i, szResult);
+ }
+ SendMessage(GetDlgItem(hDlg, i), WM_SETFONT,
+ (UINT)((i==DLG_VERLAST)?hFinePrint:hfontDlg),
+ TRUE);
+ }
+
+
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+
+ }
+
+ SendMessage(GetDlgItem(hDlg, IDC_LABEL), WM_SETFONT,
+ (WPARAM)hfontDlg,(LPARAM)TRUE);
+ if (!GetSystemOSVersion(szVersion, NULL))
+ strcpy(szVersion, "Unknown Version");
+ SetWindowText(GetDlgItem(hDlg, IDC_OSVERSION), szVersion);
+ ShowWindow(hDlg, SW_SHOW);
+ return (TRUE);
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
+ EndDialog(hDlg, TRUE);
+ DeleteObject(hfontDlg);
+ DeleteObject(hFinePrint);
+ return (TRUE);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+VOID CALLBACK MainTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ if (ap_rescanServices)
+ {
+ GetApacheServicesStatus();
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (ap_hServiceDlg)
+ {
+ SendMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+
+ }
+ }
+ else if (FindRunningServices())
+ {
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (ap_hServiceDlg)
+ {
+ SendMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+
+ }
+ }
+}
+
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ if (message == ap_uiTaskbarCreated)
+ {
+ /* reinstall tray icon */
+ ShowNotifyIcon(hWnd, NIM_ADD);
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ switch (message)
+ {
+ case WM_CREATE:
+ GetSystemOSVersion(NULL, &ap_OSVersion);
+ GetApacheServicesStatus();
+ ShowNotifyIcon(hWnd, NIM_ADD);
+ SetTimer(hWnd, 10, 1000, (TIMERPROC)MainTimerProc);
+ ap_hServiceDlg = NULL;
+ break;
+ case WM_QUIT:
+ ShowNotifyIcon(hWnd, NIM_DELETE);
+ break;
+ case WM_TRAYMESSAGE:
+ switch(lParam)
+ {
+ case WM_LBUTTONDBLCLK:
+ if (!dlgServiceOn)
+ {
+ dlgServiceOn = TRUE;
+ DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_APSRVMON_DIALOG),
+ hWnd, (DLGPROC)ServiceDlgProc);
+ dlgServiceOn = FALSE;
+ ap_hServiceDlg = NULL;
+ }
+ else if (ap_hServiceDlg)
+ {
+ /* Dirty hack to bring the window to the foreground */
+ SetWindowPos(ap_hServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetWindowPos(ap_hServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetFocus(ap_hServiceDlg);
+ }
+ break;
+ case WM_RBUTTONUP:
+ ShowTryPopupMenu(hWnd);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDM_RESTORE:
+ if (!dlgServiceOn)
+ {
+ dlgServiceOn = TRUE;
+ DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_APSRVMON_DIALOG),
+ hWnd, (DLGPROC)ServiceDlgProc);
+ dlgServiceOn = FALSE;
+ ap_hServiceDlg = NULL;
+ }
+ else if (ap_hServiceDlg)
+ SetFocus(ap_hServiceDlg);
+ break;
+ case IDM_ABOUT:
+ if (!dlgAboutOn)
+ {
+ dlgAboutOn = TRUE;
+ DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX),
+ hWnd, (DLGPROC)AboutDlgProc);
+ dlgAboutOn = FALSE;
+ ap_hwndAboutDlg = NULL;
+ }
+ else if (ap_hwndAboutDlg)
+ SetFocus(ap_hwndAboutDlg);
+
+ break;
+ case IDM_EXIT:
+ PostQuitMessage(0);
+ return TRUE;
+ break;
+ }
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return FALSE;
+}
+
+/* Create main invisible window */
+HWND CreateMainWindow(HINSTANCE hInstance)
+{
+ HWND hWnd = NULL;
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_APSRVMON);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = (LPCSTR)IDC_APSRVMON;
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_APSMALL);
+
+ if (RegisterClassEx(&wcex))
+ {
+ hWnd = CreateWindow(szWindowClass, szTitle,
+ 0, 0, 0, 0, 0,
+ NULL, NULL, hInstance, NULL);
+ }
+
+ return hWnd;
+
+}
+
+
+int WINAPI WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow)
+{
+ HWND hwnd;
+ MSG msg;
+ /* single instance mutex */
+ HANDLE hMutex = CreateMutex(NULL, FALSE, "APSRVMON_MUTEX");
+ if((hMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
+ {
+ if (hMutex)
+ CloseHandle(hMutex);
+
+ return 0;
+ }
+
+ InitCommonControls();
+ ap_hInstance = hInstance;
+
+ LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ LoadString(hInstance, IDC_APSRVMON, szWindowClass, MAX_LOADSTRING);
+ ap_icoStop = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP));
+ ap_icoRun = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICORUN));
+ ap_uiTaskbarCreated = RegisterWindowMessage("TaskbarCreated");
+
+ ZeroMemory(ap_stServices, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+ hwnd = CreateMainWindow(hInstance);
+ if (hwnd != NULL)
+ {
+ while (GetMessage(&msg, NULL, 0, 0) == TRUE)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ ap_ClearServicesSt();
+ }
+ CloseHandle(hMutex);
+ return 0;
+}
diff --git a/support/win32/ApacheMonitor.dsp b/support/win32/ApacheMonitor.dsp
new file mode 100644
index 00000000000..8699a75baaa
--- /dev/null
+++ b/support/win32/ApacheMonitor.dsp
@@ -0,0 +1,143 @@
+# Microsoft Developer Studio Project File - Name="ApacheMonitor" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=ApacheMonitor - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ApacheMonitor.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ApacheMonitor.mak" CFG="ApacheMonitor - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ApacheMonitor - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "ApacheMonitor - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fd"Release/ApacheMonitor" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib version.lib /nologo /subsystem:windows /map /machine:I386
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fd"Debug/ApacheMonitor" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib version.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "ApacheMonitor - Win32 Release"
+# Name "ApacheMonitor - Win32 Debug"
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "*.rc,*.ico,*.bmp"
+# Begin Source File
+
+SOURCE=.\apache_header.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.rc
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\aprun.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\apsmall.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\apsrvmon.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\apstop.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\srun.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstop.bmp
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.c
+# End Source File
+# End Target
+# End Project
diff --git a/support/win32/ApacheMonitor.h b/support/win32/ApacheMonitor.h
new file mode 100644
index 00000000000..4bdfc15914d
--- /dev/null
+++ b/support/win32/ApacheMonitor.h
@@ -0,0 +1,49 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by ApSrvmon.rc
+//
+#define IDD_APSRVMON_DIALOG 101
+#define IDD_ABOUTBOX 102
+#define IDS_APP_TITLE 103
+#define IDM_RESTORE 104
+#define IDM_ABOUT 105
+#define IDM_EXIT 106
+#define IDI_APSRVMONM 107
+#define IDI_APSRVMON 108
+#define IDI_APSMALL 109
+#define IDC_APSRVMON 110
+#define IDS_VERSION_ERROR 111
+#define IDS_VER_INFO_LANG 112
+#define IDR_MAINFRAME 128
+#define IDI_ICOSTOP 129
+#define IDI_ICORUN 130
+#define IDC_STATBAR 134
+#define DLG_VERFIRST 140
+#define IDC_COMPANY 140
+#define IDC_FILEDESC 141
+#define IDC_PRODVER 142
+#define IDC_COPYRIGHT 143
+#define IDC_OSVERSION 144
+#define IDC_TRADEMARK 145
+#define DLG_VERLAST 145
+#define IDC_LABEL 146
+#define IDB_BMPSTOP 155
+#define IDB_BMPRUN 156
+#define IDB_BMPHEADER 158
+#define IDL_SERVICES 1003
+#define IDC_SSTART 1004
+#define IDC_SSTOP 1005
+#define IDC_SRESTART 1006
+#define IDC_SUNINSTALL 1008
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 159
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1009
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/support/win32/ApacheMonitor.ico b/support/win32/ApacheMonitor.ico
new file mode 100644
index 00000000000..cd28dc520c4
Binary files /dev/null and b/support/win32/ApacheMonitor.ico differ
diff --git a/support/win32/apache_header.bmp b/support/win32/apache_header.bmp
new file mode 100644
index 00000000000..7b116fc3da7
Binary files /dev/null and b/support/win32/apache_header.bmp differ
diff --git a/support/win32/aprun.ico b/support/win32/aprun.ico
new file mode 100644
index 00000000000..dbd5832602c
Binary files /dev/null and b/support/win32/aprun.ico differ
diff --git a/support/win32/apstop.ico b/support/win32/apstop.ico
new file mode 100644
index 00000000000..fba49ad2926
Binary files /dev/null and b/support/win32/apstop.ico differ
diff --git a/support/win32/srun.bmp b/support/win32/srun.bmp
new file mode 100644
index 00000000000..90ecd46f178
Binary files /dev/null and b/support/win32/srun.bmp differ
diff --git a/support/win32/sstop.bmp b/support/win32/sstop.bmp
new file mode 100644
index 00000000000..ba73d87aecb
Binary files /dev/null and b/support/win32/sstop.bmp differ
diff --git a/support/win32/wintty.c b/support/win32/wintty.c
new file mode 100644
index 00000000000..28c5979cce0
--- /dev/null
+++ b/support/win32/wintty.c
@@ -0,0 +1,328 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* --------------------------------------------------------------------
+ *
+ * wintty : a Apache/WinNT support utility for monitoring and
+ * reflecting user feedback from the Apache process via
+ * stdin/stdout, even as running within the service context.
+ *
+ * Originally contributed by William Rowe
+ *
+ * Note: this implementation is _very_ experimental, and error handling
+ * is far from complete. Using it as a cgi or pipe process allows the
+ * programmer to discover if facilities such as reliable piped logs
+ * are working as expected, or answer operator prompts that would
+ * otherwise be discarded by the service process.
+ *
+ * Also note the isservice detection semantics, which far exceed any
+ * mechanism we have discovered thus far.
+ *
+ * --------------------------------------------------------------------
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+const char *options =
+"Syntax: wintty [opts] [-?]\n\n"
+" opts: -c{haracter} or -l{ine} input\n"
+"\t-q{uiet} or -e{cho} input\n"
+"\topts: -u{nprocessed} or -p{rocessed} input\n"
+"\topts: -n{owrap} or -w{rap} output lines\n"
+"\topts: -f{ormatted} or -r{aw} output lines\n"
+"\topts: -v{erbose} error checking\n"
+"\topts: -? for this message\n\n";
+
+HANDLE herrout;
+BOOL verbose = FALSE;
+
+void printerr(char *fmt, ...)
+{
+ char str[1024];
+ va_list args;
+ DWORD len;
+ if (!verbose)
+ return;
+ va_start(args, fmt);
+ wvsprintf(str, fmt, args);
+ WriteFile(herrout, str, len = strlen(str), &len, NULL);
+}
+
+DWORD WINAPI feedback(LPVOID pipeout);
+
+int main(int argc, char** argv)
+{
+ char str[1024], *contitle;
+ HANDLE hproc, thread;
+ HANDLE hwinsta, hsavewinsta;
+ HANDLE hdesk, hsavedesk;
+ HANDLE conin, conout;
+ HANDLE pipein, pipeout;
+ HANDLE hstdin, hstdout, hstderr;
+ DWORD conmode;
+ DWORD newinmode = 0, notinmode = 0;
+ DWORD newoutmode = 0, notoutmode = 0;
+ DWORD tid;
+ DWORD len;
+ BOOL isservice = FALSE;
+
+ while (--argc) {
+ ++argv;
+ if (**argv == '/' || **argv == '-') {
+ switch (tolower((*argv)[1])) {
+ case 'c':
+ notinmode |= ENABLE_LINE_INPUT; break;
+ case 'l':
+ newinmode |= ENABLE_LINE_INPUT; break;
+ case 'q':
+ notinmode |= ENABLE_ECHO_INPUT; break;
+ case 'e':
+ newinmode |= ENABLE_ECHO_INPUT; break;
+ case 'u':
+ notinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'p':
+ newinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'n':
+ notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'w':
+ newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'r':
+ notoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'f':
+ newoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'v':
+ verbose = TRUE;
+ break;
+ case 't':
+ contitle = *(++argv);
+ --argc;
+ break;
+ case '?':
+ printf(options);
+ exit(1);
+ default:
+ printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+ else {
+ printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+
+ hproc = GetCurrentProcess();
+ herrout = hstderr = GetStdHandle(STD_ERROR_HANDLE);
+ if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstderr,
+ hproc, &herrout, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stderr) failed (%d)\n", GetLastError());
+ }
+
+ hstdin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstdin,
+ hproc, &pipein, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stdin) failed (%d)\n", GetLastError());
+ }
+
+ hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstdout,
+ hproc, &pipeout, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stdout) failed (%d)\n", GetLastError());
+ }
+
+ hsavewinsta = GetProcessWindowStation();
+ if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
+ printerr("GetProcWinSta() failed (%d)\n", GetLastError());
+ }
+ else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
+ printerr("GetUserObjectInfo(GetProcWinSta) failed (%d)\n", GetLastError());
+ CloseHandle(hsavewinsta);
+ }
+ else if (strnicmp(str, "Service-", 8) == 0) {
+ isservice = TRUE;
+ }
+ else
+ CloseHandle(hsavewinsta);
+ SetLastError(0);
+
+ if (!FreeConsole())
+ printerr("DupHandle(stdout) failed (%d)\n", GetLastError());
+
+ if (isservice) {
+ hwinsta = OpenWindowStation("WinSta0", TRUE,
+ WINSTA_ACCESSCLIPBOARD
+ | WINSTA_ACCESSGLOBALATOMS
+ | WINSTA_ENUMDESKTOPS
+ | WINSTA_ENUMERATE
+ | WINSTA_READATTRIBUTES
+ | WINSTA_READSCREEN
+ | WINSTA_WRITEATTRIBUTES);
+ if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
+ printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ else if (!SetProcessWindowStation(hwinsta)) {
+ printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ hsavedesk = GetThreadDesktop(GetCurrentThreadId());
+ hdesk = OpenDesktop("Default", 0, TRUE,
+ DESKTOP_READOBJECTS
+ | DESKTOP_CREATEWINDOW
+ | DESKTOP_CREATEMENU
+ | DESKTOP_HOOKCONTROL
+ | DESKTOP_JOURNALRECORD
+ | DESKTOP_JOURNALPLAYBACK
+ | DESKTOP_ENUMERATE
+ | DESKTOP_WRITEOBJECTS);
+ if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
+ printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
+ }
+ else if (!SetThreadDesktop(hdesk)) {
+ printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
+ }
+ }
+
+ if (!AllocConsole()) {
+ printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
+ }
+
+ if (contitle && !SetConsoleTitle(contitle)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+
+ conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!conout || conout == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conout, &conmode)) {
+ printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode) & ~notoutmode))) {
+ printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n", conmode, GetLastError());
+ }
+
+ conin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!conin || conin == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conin, &conmode)) {
+ printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode) & ~notinmode))) {
+ printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n", conmode, GetLastError());
+ }
+
+ thread = CreateThread(NULL, 0, feedback, (LPVOID)pipeout, 0, &tid);
+
+ while (ReadFile(pipein, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(conout, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from stdin (%d)\n", GetLastError());
+
+ CloseHandle(pipeout);
+ if (!GetConsoleTitle(str, sizeof(str))) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ else {
+ strcat(str, " - [Finished]");
+ if (!SetConsoleTitle(str)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ }
+
+ WaitForSingleObject(thread, INFINITE);
+ FreeConsole();
+ CloseHandle(herrout);
+ if (isservice) {
+ if (!SetProcessWindowStation(hsavewinsta)) {
+ len = GetLastError();
+ }
+ if (!SetThreadDesktop(hsavedesk)) {
+ len = GetLastError();
+ }
+ CloseDesktop(hdesk);
+ CloseWindowStation(hwinsta);
+ }
+ return 0;
+}
+
+
+DWORD WINAPI feedback(LPVOID arg)
+{
+ HANDLE conin;
+ HANDLE pipeout = (HANDLE)arg;
+ char *str[1024];
+ DWORD len;
+
+ conin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!conin) {
+ len = GetLastError();
+ }
+
+ while (ReadFile(conin, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(pipeout, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from Console (%d)\n", GetLastError());
+
+ return 0;
+}
diff --git a/support/win32/wintty.dsp b/support/win32/wintty.dsp
new file mode 100644
index 00000000000..bf62b5e80c1
--- /dev/null
+++ b/support/win32/wintty.dsp
@@ -0,0 +1,90 @@
+# Microsoft Developer Studio Project File - Name="wintty" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=wintty - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/wintty" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /machine:I386
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/wintty" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "wintty - Win32 Release"
+# Name "wintty - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\wintty.c
+# End Source File
+# End Target
+# End Project